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

SOFTDEVICE ASSERTION 0x0002715e

Hello,

Looking for some background info for SOFTDEVICE ASSERTION 0x0002715e.
sdk 15.3, SD s132_nrf52_6.1.1

Maybe related,
there is no Assert if fds_record_write() is done before connecting,
but Assert received during fds_record_write() after connecting and CTS received (current time service).

thank-you,

Parents
  • Hi Simon, 

    Sorry for the delay. 

    Could you try with a lower NRF_FSTORAGE_SD_MAX_WRITE_SIZE setting, 1024 for instance?

    Is it possible to provide the debug log? 

    -Amanda H.

  • I had been using WRITE_SIZE 1024 from another suggestion on devzone, but still the same issue.
    The other bit of code merged was the Calendar example,
    and it seems the function nrf_cal_set_callback() is what seems to be causing the Assert.
    Without the callback(), the fds_record_write() is working ok.
    I checked the suggestion by Torbjørn (ovrebekk), to make sure RTC2 is being used, and it is.

    I merged sdk 15.3 CTS with Calendar and added the FDS write() to test on DK832 and reproduce the issue.
    The fault happens in fds_write_1() during fds_record_write(), line 248 on SES.
    (After connecting on nRF Connect, press button 1 on the DK).

    thank-you,

    <00> info>�app:�Current�Time�service�client�started.
    00> 
    <00> debug>�app:�pm_whitelist_get�returns�1�addr�in�whitelist�and�1�irk�whitelist
    00> 
    <00> info>�app:�Fast�advertising�with�WhiteList
    00> 
    00> bme280_read_3�top
    00> fds_write_1�mid�1
    00> fds_write_1�mid�2
    00> rec_id sample1 sample2 sample3 sample4
    00> C �1 �2 �3 �4 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x10
    00> 
    <00> info>�app:�Connected.
    00> 
    <00> info>�app:�ble_evt_handler�connected�->�fds_write_1.
    00> 
    <00> debug>�nrf_ble_gatt:�Peer�on�connection�0x0�requested�a�data�length�of�27�bytes.
    00> 
    <00> debug>�nrf_ble_gatt:�Updating�data�length�to�27�on�connection�0x0.
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x23
    00> 
    <00> debug>�nrf_ble_gatt:�Data�length�updated�to�27�on�connection�0x0.
    00> 
    <00> debug>�nrf_ble_gatt:�max_rx_octets:�27
    00> 
    <00> debug>�nrf_ble_gatt:�max_tx_octets:�27
    00> 
    <00> debug>�nrf_ble_gatt:�max_rx_time:�328
    00> 
    <00> debug>�nrf_ble_gatt:�max_tx_time:�2120
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x24
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x14
    00> 
    <00> info>�peer_manager_handler:�Connection�secured:�role:�Peripheral,�conn_handle:�0,�procedure:�Encryption
    00> 
    <00> debug>�ble_db_disc:�Starting�discovery�of�service�with�UUID�0x1805�on�connection�handle�0x0.
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x1A
    00> 
    <00> debug>�ble_db_disc:�Found�service�UUID�0x1805.
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x30
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x32
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x32
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x33
    00> 
    <00> debug>�ble_db_disc:�Discovery�of�service�with�UUID�0x1805�completed�with�success�on�connection�handle�0x0.
    00> 
    <00> debug>�ble_cts_c:�Database�Discovery�handler�called�with�event�0x0
    00> 
    <00> info>�ble_cts_c:�Current�Time�Service�discovered�at�peer.
    00> 
    <00> info>�app:�Current�Time�Service�discovered�on�server.
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x33
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x12
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x36
    00> 
    <00> debug>�ble_cts_c:�Current�Time�read�response�data:
    00> 
    <00> debug>�ble_cts_c:��E4�07�0B�13�15�10�32�04|......2.
    00> 
    <00> debug>�ble_cts_c:��C5�00������������������|..������
    00> 
    <00> info>�app:�Current�Time�received.
    00> 
    00> Epoch:�1605820643
    00> New�time:�11/19/20�-�21:17:18
    00> bme280_read_3�top
    00> fds_write_1�mid�1
    

    /**
     * Copyright (c) 2014 - 2019, 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.
     *
     */
    /** @file
     *
     * @defgroup ble_sdk_app_cts_c_main main.c
     * @{
     * @ingroup ble_sdk_app_cts_c
     * @brief Current Time Profile sample application.
     *
     * This file contains the source code for a sample application that uses Current Time Service.
     * This is the client role of the profile, implemented on a peripheral device.
     * When a central device connects, the application will trigger a security procedure (if this is not done
     * by the central side first). Completion of the security procedure will trigger a service
     * discovery. When the Current Time Service and Characteristic have been discovered on the
     * server, pressing button 1 will trigger a read of the current time and print it on the UART.
     *
     */
    
    /** ADD TO CTS
    
    #define NRF_LOG_DEFERRED 1
    #define NRF_LOG_DEFAULT_LEVEL 4
    DEBUG
    
    #include <stdio.h>
    #include "nrf_calendar.h"
    static bool run_time_updates = true;
    
    
    #include "SEGGER_RTT.h"
    #include "SEGGER_RTT_Conf.h"
    
    */
    
    
    #include <stdint.h>
    #include <string.h>
    #include "nrf.h"
    #include "app_error.h"
    #include "app_scheduler.h"
    #include "app_timer.h"
    #include "ble.h"
    #include "ble_cts_c.h"
    #include "ble_db_discovery.h"
    #include "ble_hci.h"
    #include "ble_srv_common.h"
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_conn_params.h"
    #include "bsp_btn_ble.h"
    #include "peer_manager.h"
    #include "peer_manager_handler.h"
    #include "nordic_common.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_soc.h"
    #include "nrf_sdh_ble.h"
    #include "fds.h"
    #include "ble_conn_state.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_ble_qwr.h"
    #include "nrf_pwr_mgmt.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    /* for Calendar: */
    #include <stdio.h>
    #include "nrf_calendar.h"
    static bool run_time_updates = true;
    
    #include "SEGGER_RTT.h"
    #include "SEGGER_RTT_Conf.h"
    
    
    #define DEVICE_NAME                     "Nordic_CTS"                                /**< Name of the device. Will be included in the advertising data. */
    
    #define APP_BLE_OBSERVER_PRIO           3                                           /**< Application's BLE observer priority. You shouldn't need to modify this value. */
    #define APP_BLE_CONN_CFG_TAG            1                                           /**< A tag identifying the SoftDevice BLE configuration. */
    
    #define APP_ADV_FAST_INTERVAL           0x0028                                      /**< Fast advertising interval (in units of 0.625 ms). The default value corresponds to 25 ms. */
    #define APP_ADV_SLOW_INTERVAL           0x0C80                                      /**< Slow advertising interval (in units of 0.625 ms). The default value corresponds to 2 seconds. */
    
    #define APP_ADV_FAST_DURATION           3000                                        /**< The advertising duration of fast advertising in units of 10 milliseconds. */
    #define APP_ADV_SLOW_DURATION           18000                                       /**< The advertising duration of slow advertising in units of 10 milliseconds. */
    
    
    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(500, UNIT_1_25_MS)            /**< Minimum acceptable connection interval (0.5 seconds). */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(1000, UNIT_1_25_MS)           /**< Maximum acceptable connection interval (1 second). */
    #define SLAVE_LATENCY                   0                                           /**< Slave latency. */
    #define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)             /**< Connection supervisory time-out (4 seconds). */
    #define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000)                       /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
    #define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000)                      /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
    #define MAX_CONN_PARAMS_UPDATE_COUNT    3                                           /**< Number of attempts before giving up the connection parameter negotiation. */
    
    #define SEC_PARAM_TIMEOUT               30                                          /**< Time-out for pairing request or security request (in seconds). */
    #define SEC_PARAM_BOND                  1                                           /**< Perform bonding. */
    #define SEC_PARAM_MITM                  0                                           /**< Man In The Middle protection requirement. */
    #define SEC_PARAM_LESC                  0                                           /**< LE Secure Connections not enabled. */
    #define SEC_PARAM_KEYPRESS              0                                           /**< Keypress notifications not enabled. */
    #define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_NONE                        /**< I/O capabilities. */
    #define SEC_PARAM_OOB                   0                                           /**< Out Of Band data availability. */
    #define SEC_PARAM_MIN_KEY_SIZE          7                                           /**< Minimum encryption key size. */
    #define SEC_PARAM_MAX_KEY_SIZE          16                                          /**< Maximum encryption key size. */
    
    #define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE                   /**< Maximum size of scheduler events. Note that scheduler BLE stack events do not contain any data, as the events are being pulled from the stack in the event handler. */
    #ifdef SVCALL_AS_NORMAL_FUNCTION
    #define SCHED_QUEUE_SIZE                20                                          /**< Maximum number of events in the scheduler queue. More is needed in case of Serialization. */
    #else
    #define SCHED_QUEUE_SIZE                10                                          /**< Maximum number of events in the scheduler queue. */
    #endif
    
    #define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    
    BLE_CTS_C_DEF(m_cts_c);                                                             /**< Current Time service instance. */
    NRF_BLE_GATT_DEF(m_gatt);                                                           /**< GATT module instance. */
    NRF_BLE_QWR_DEF(m_qwr);                                                             /**< Context for the Queued Write module.*/
    BLE_ADVERTISING_DEF(m_advertising);                                                 /**< Advertising module instance. */
    BLE_DB_DISCOVERY_DEF(m_ble_db_discovery);                                           /**< DB discovery module instance. */
    
    static pm_peer_id_t m_peer_id;                                                      /**< Device reference handle to the current bonded central. */
    static uint16_t     m_cur_conn_handle = BLE_CONN_HANDLE_INVALID;                    /**< Handle of the current connection. */
    
    static pm_peer_id_t m_whitelist_peers[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];            /**< List of peers currently in the whitelist. */
    static uint32_t     m_whitelist_peer_cnt;                                           /**< Number of peers currently in the whitelist. */
    
    static ble_uuid_t m_adv_uuids[] = {{BLE_UUID_CURRENT_TIME_SERVICE, BLE_UUID_TYPE_BLE}};
    
    static char const * day_of_week[] =
    {
        "Unknown",
        "Monday",
        "Tuesday",
        "Wednesday",
        "Thursday",
        "Friday",
        "Saturday",
        "Sunday"
    };
    
    static char const * month_of_year[] =
    {
        "Unknown",
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
    };
    
    
    //***** fds_write_1 ***** START
    
    #define FILE_ID     0x1111
    #define REC_KEY     0x1111
    
    typedef struct
    {
        uint32_t sample1;
        uint32_t sample2;
        uint32_t sample3;
        uint32_t sample4;
    } sensor_data;
    
    /* Dummy configuration data. */
    static sensor_data sensor_data_sample =
    {
        .sample1  = 0,
        .sample2  = 0,
        .sample3  = 0,
        .sample4  = 0,
    };
    
    /* A record containing dummy configuration data. */
    static fds_record_t const sensor_data_record =
    {
        .file_id           = FILE_ID,
        .key               = REC_KEY,
        .data.p_data       = &sensor_data_sample,
        .data.length_words = (sizeof(sensor_data_sample) + 3) / sizeof(uint32_t),
    };
    
    /**@brief   Wait for fds to initialize. */
    static void fds_write_1(void)
    {
        uint32_t err_code;   
        uint32_t *data;
    
        ret_code_t rc;
        fds_record_desc_t   record_desc;
    
    //    NRF_LOG_INFO("fds_write_1 top\r\n");
        SEGGER_RTT_printf(0,"bme280_read_3 top\r\n");
    
        sensor_data_sample.sample1 = 0x00000001;
        sensor_data_sample.sample2 = 0x00000002;
        sensor_data_sample.sample3 = 0x00000003;
        sensor_data_sample.sample4 = 0x00000004;
    
    //    NRF_LOG_INFO("fds_write_1 mid 1\r\n");
        SEGGER_RTT_printf(0,"fds_write_1 mid 1\r\n");
    
        rc = fds_record_write(&record_desc, &sensor_data_record);
    
    //    NRF_LOG_INFO("fds_write_1 mid 2\r\n");
        SEGGER_RTT_printf(0,"fds_write_1 mid 2\r\n");
    
        if (rc != NRF_SUCCESS)
        {
            /* Handle error. */
    //          NRF_LOG_INFO("fds_write_1 Record not write.\r\n");
              SEGGER_RTT_printf(0,"fds_write_5 Record not write.\r\n");
        }
        else
        {
          data = (uint32_t *) sensor_data_record.data.p_data;
    
    //      NRF_LOG_INFO("rec_id\tsample1\tsample2\tsample3\tsample4\r\n");
    //      NRF_LOG_INFO("%x\t\t %x\t %x\t %x\t %x\t\r\n", record_desc.record_id, data[0], data[1], data[2], data[3]);
          SEGGER_RTT_printf(0,"rec_id\tsample1\tsample2\tsample3\tsample4\r\n");
          SEGGER_RTT_printf(0,"%x\t\t %x\t %x\t %x\t %x\t\r\n", record_desc.record_id, data[0], data[1], data[2], data[3]);
        }
    }
    
    //***** fds_write_1 ***** END
    
    
    /**@brief Callback function for asserts in the SoftDevice.
     *
     * @details This function will be called in case of an assert in the SoftDevice.
     *
     * @warning This handler is an example only and does not fit a final product. You need to analyze
     *          how your product is supposed to react in case of Assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in] line_num  Line number of the failing ASSERT call.
     * @param[in] file_name File name of the failing ASSERT call.
     */
    void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    {
        app_error_handler(DEAD_BEEF, line_num, p_file_name);
    }
    
    
    /**@brief Fetch the list of peer manager peer IDs.
     *
     * @param[inout] p_peers   The buffer where to store the list of peer IDs.
     * @param[inout] p_size    In: The size of the @p p_peers buffer.
     *                         Out: The number of peers copied in the buffer.
     */
    static void peer_list_get(pm_peer_id_t * p_peers, uint32_t * p_size)
    {
        pm_peer_id_t peer_id;
        uint32_t     peers_to_copy;
    
        peers_to_copy = (*p_size < BLE_GAP_WHITELIST_ADDR_MAX_COUNT) ?
                         *p_size : BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
        peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
        *p_size = 0;
    
        while ((peer_id != PM_PEER_ID_INVALID) && (peers_to_copy--))
        {
            p_peers[(*p_size)++] = peer_id;
            peer_id = pm_next_peer_id_get(peer_id);
        }
    }
    
    
    /**@brief Clear bond information from persistent storage.
     */
    static void delete_bonds(void)
    {
        ret_code_t err_code;
    
        NRF_LOG_INFO("Erase bonds!");
    
        err_code = pm_peers_delete();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for starting advertising.
     */
    static void advertising_start(bool erase_bonds)
    {
        if (erase_bonds == true)
        {
            delete_bonds();
            // Advertising is started by PM_EVT_PEERS_DELETE_SUCCEEDED event.
        }
        else
        {
            ret_code_t ret;
    
            memset(m_whitelist_peers, PM_PEER_ID_INVALID, sizeof(m_whitelist_peers));
            m_whitelist_peer_cnt = (sizeof(m_whitelist_peers) / sizeof(pm_peer_id_t));
    
            peer_list_get(m_whitelist_peers, &m_whitelist_peer_cnt);
    
            ret = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt);
            APP_ERROR_CHECK(ret);
    
            // Setup the device identies list.
            // Some SoftDevices do not support this feature.
            ret = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt);
            if (ret != NRF_ERROR_NOT_SUPPORTED)
            {
                APP_ERROR_CHECK(ret);
            }
    
            ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
            APP_ERROR_CHECK(ret);
        }
    }
    
    
    /**@brief Function for handling Peer Manager events.
     *
     * @param[in] p_evt  Peer Manager event.
     */
    static void pm_evt_handler(pm_evt_t const * p_evt)
    {
        ret_code_t err_code;
    
        pm_handler_on_pm_evt(p_evt);
        pm_handler_flash_clean(p_evt);
    
        switch (p_evt->evt_id)
        {
            case PM_EVT_CONN_SEC_SUCCEEDED:
            {
                m_peer_id = p_evt->peer_id;
    
                // Discover peer's services.
                err_code  = ble_db_discovery_start(&m_ble_db_discovery, p_evt->conn_handle);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case PM_EVT_PEERS_DELETE_SUCCEEDED:
            {
                advertising_start(false);
            } break;
    
            case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
            {
                // Note: You should check on what kind of white list policy your application should use.
                if (     p_evt->params.peer_data_update_succeeded.flash_changed
                     && (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_BONDING))
                {
                    NRF_LOG_DEBUG("New Bond, add the peer to the whitelist if possible");
                    NRF_LOG_DEBUG("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d",
                                   m_whitelist_peer_cnt + 1,
                                   BLE_GAP_WHITELIST_ADDR_MAX_COUNT);
    
                    if (m_whitelist_peer_cnt < BLE_GAP_WHITELIST_ADDR_MAX_COUNT)
                    {
                        // Bonded to a new peer, add it to the whitelist.
                        m_whitelist_peers[m_whitelist_peer_cnt++] = m_peer_id;
    
                        // The whitelist has been modified, update it in the Peer Manager.
                        err_code = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt);
                        if (err_code != NRF_ERROR_NOT_SUPPORTED)
                        {
                            APP_ERROR_CHECK(err_code);
                        }
    
                        err_code = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt);
                        APP_ERROR_CHECK(err_code);
                    }
                }
            } break;
    
            default:
                break;
        }
    }
    
    void print_current_time()
    {
        printf("Epoch:\t%d\r\n", nrf_cal_get_epoch());
        printf("New time:\t%s\r\n", nrf_cal_get_time_string(false));
    }
    
    /* set run_time_updates=false to stop calendar updates*/
    void calendar_updated()
    {
        if(run_time_updates)
        {
    //        print_current_time();
    
            fds_write_1();
    
        }
    }
    
    
    
    /**@brief Function for handling the Current Time Service errors.
     *
     * @param[in]  nrf_error  Error code containing information about what went wrong.
     */
    static void current_time_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for handling the Current Time Service errors.
     *
     * @param[in] p_evt  Event received from the Current Time Service client.
     */
    static void current_time_print(ble_cts_c_evt_t * p_evt)
    {
    //    NRF_LOG_INFO("\r\nCurrent Time:");
    //    NRF_LOG_INFO("\r\nDate:");
    //
    //    NRF_LOG_INFO("\tDay of week   %s", (uint32_t)day_of_week[p_evt->
    //                                                         params.
    //                                                         current_time.
    //                                                         exact_time_256.
    //                                                         day_date_time.
    //                                                         day_of_week]);
    //
    //    if (p_evt->params.current_time.exact_time_256.day_date_time.date_time.day == 0)
    //    {
    //        NRF_LOG_INFO("\tDay of month  Unknown");
    //    }
    //    else
    //    {
    //        NRF_LOG_INFO("\tDay of month  %i",
    //                       p_evt->params.current_time.exact_time_256.day_date_time.date_time.day);
    //    }
    //
    //    NRF_LOG_INFO("\tMonth of year %s",
    //    (uint32_t)month_of_year[p_evt->params.current_time.exact_time_256.day_date_time.date_time.month]);
    //    if (p_evt->params.current_time.exact_time_256.day_date_time.date_time.year == 0)
    //    {
    //        NRF_LOG_INFO("\tYear          Unknown");
    //    }
    //    else
    //    {
    //        NRF_LOG_INFO("\tYear          %i",
    //                       p_evt->params.current_time.exact_time_256.day_date_time.date_time.year);
    //    }
    //    NRF_LOG_INFO("\r\nTime:");
    //    NRF_LOG_INFO("\tHours     %i",
    //                   p_evt->params.current_time.exact_time_256.day_date_time.date_time.hours);
    //    NRF_LOG_INFO("\tMinutes   %i",
    //                   p_evt->params.current_time.exact_time_256.day_date_time.date_time.minutes);
    //    NRF_LOG_INFO("\tSeconds   %i",
    //                   p_evt->params.current_time.exact_time_256.day_date_time.date_time.seconds);
    //    NRF_LOG_INFO("\tFractions %i/256 of a second",
    //                   p_evt->params.current_time.exact_time_256.fractions256);
    //
    //    NRF_LOG_INFO("\r\nAdjust reason:\r");
    //    NRF_LOG_INFO("\tDaylight savings %x",
    //                   p_evt->params.current_time.adjust_reason.change_of_daylight_savings_time);
    //    NRF_LOG_INFO("\tTime zone        %x",
    //                   p_evt->params.current_time.adjust_reason.change_of_time_zone);
    //    NRF_LOG_INFO("\tExternal update  %x",
    //                   p_evt->params.current_time.adjust_reason.external_reference_time_update);
    //    NRF_LOG_INFO("\tManual update    %x",
    //                   p_evt->params.current_time.adjust_reason.manual_time_update);
    
        uint32_t year, month, day, hour, minute, second;
    
        /* time received from cts populates variables */
        year = p_evt->params.current_time.exact_time_256.day_date_time.date_time.year;
        month = p_evt->params.current_time.exact_time_256.day_date_time.date_time.month;
        day = p_evt->params.current_time.exact_time_256.day_date_time.date_time.day;
        hour = p_evt->params.current_time.exact_time_256.day_date_time.date_time.hours;
        minute = p_evt->params.current_time.exact_time_256.day_date_time.date_time.minutes;
        second = p_evt->params.current_time.exact_time_256.day_date_time.date_time.seconds;
    
        /* variables from cts set calendar */
        nrf_cal_set_time(year, month, day, hour, minute, second);
    
        /* function calendar_updated called every 5 seconds */
        nrf_cal_set_callback(calendar_updated, 5);
    
    
    
    }
    
    
    /**@brief Function for the timer initialization.
     *
     * @details Initializes the timer module.
     */
    static void timers_init(void)
    {
        ret_code_t err_code;
    
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the Current Time Service client events.
     *
     * @details This function will be called for all events in the Current Time Service client that
     *          are passed to the application.
     *
     * @param[in] p_evt Event received from the Current Time Service client.
     */
    static void on_cts_c_evt(ble_cts_c_t * p_cts, ble_cts_c_evt_t * p_evt)
    {
        ret_code_t err_code;
    
        switch (p_evt->evt_type)
        {
            case BLE_CTS_C_EVT_DISCOVERY_COMPLETE:
                NRF_LOG_INFO("Current Time Service discovered on server.");
                err_code = ble_cts_c_handles_assign(&m_cts_c,
                                                    p_evt->conn_handle,
                                                    &p_evt->params.char_handles);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_CTS_C_EVT_DISCOVERY_FAILED:
                NRF_LOG_INFO("Current Time Service not found on server. ");
                // CTS not found in this case we just disconnect. There is no reason to stay
                // in the connection for this simple app since it all wants is to interact with CT
                if (p_evt->conn_handle != BLE_CONN_HANDLE_INVALID)
                {
                    err_code = sd_ble_gap_disconnect(p_evt->conn_handle,
                                                     BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                    APP_ERROR_CHECK(err_code);
                }
                break;
    
            case BLE_CTS_C_EVT_DISCONN_COMPLETE:
                NRF_LOG_INFO("Disconnect Complete.");
                break;
    
            case BLE_CTS_C_EVT_CURRENT_TIME:
                NRF_LOG_INFO("Current Time received.");
                current_time_print(p_evt);
    
    //            NRF_LOG_INFO("on_cts_c_evt current_time_print-> fds_write_1.");
    //            fds_write_1();
    
                break;
    
            case BLE_CTS_C_EVT_INVALID_TIME:
                NRF_LOG_INFO("Invalid Time received.");
                break;
    
            default:
                break;
        }
    }
    
    
    /**@brief Function for the GAP initialization.
     *
     * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
     *          device including the device name, appearance, and the preferred connection parameters.
     */
    static void gap_params_init(void)
    {
        ret_code_t              err_code;
        ble_gap_conn_params_t   gap_conn_params;
        ble_gap_conn_sec_mode_t sec_mode;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    
        err_code = sd_ble_gap_device_name_set(&sec_mode,
                                              (const uint8_t *)DEVICE_NAME,
                                              strlen(DEVICE_NAME));
        APP_ERROR_CHECK(err_code);
    
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));
    
        gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
        gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
        gap_conn_params.slave_latency     = SLAVE_LATENCY;
        gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;
    
        err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the GATT module.
     */
    static void gatt_init(void)
    {
        ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling Queued Write Module errors.
     *
     * @details A pointer to this function will be passed to each service which may need to inform the
     *          application about an error.
     *
     * @param[in]   nrf_error   Error code containing information about what went wrong.
     */
    static void nrf_qwr_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for initializing services that will be used by the application.
     */
    static void services_init(void)
    {
        ret_code_t         err_code;
        ble_cts_c_init_t   cts_init = {0};
        nrf_ble_qwr_init_t qwr_init = {0};
    
        // Initialize Queued Write Module.
        qwr_init.error_handler = nrf_qwr_error_handler;
    
        err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
        APP_ERROR_CHECK(err_code);
    
        // Initialize CTS.
        cts_init.evt_handler   = on_cts_c_evt;
        cts_init.error_handler = current_time_error_handler;
        err_code               = ble_cts_c_init(&m_cts_c, &cts_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the Connection Parameters module.
     *
     * @details This function will be called for all events in the Connection Parameters module that
     *          are passed to the application.
     *          @note All this function does is to disconnect. This could have been done by simply
     *                setting the disconnect_on_fail config parameter, but instead we use the event
     *                handler mechanism to demonstrate its use.
     *
     * @param[in] p_evt  Event received from the Connection Parameters module.
     */
    static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
    {
        ret_code_t err_code;
    
        if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
        {
            err_code = sd_ble_gap_disconnect(m_cur_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    
    /**@brief Function for handling a Connection Parameters error.
     *
     * @param[in]   nrf_error   Error code containing information about what went wrong.
     */
    static void conn_params_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for initializing the Connection Parameters module.
     */
    static void conn_params_init(void)
    {
        ret_code_t             err_code;
        ble_conn_params_init_t cp_init;
    
        memset(&cp_init, 0, sizeof(cp_init));
    
        cp_init.p_conn_params                  = NULL;
        cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
        cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
        cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
        cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
        cp_init.disconnect_on_fail             = false;
        cp_init.evt_handler                    = on_conn_params_evt;
        cp_init.error_handler                  = conn_params_error_handler;
    
        err_code = ble_conn_params_init(&cp_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling Database Discovery events.
     *
     * @details This function is a callback function to handle events from the database discovery module.
     *          Depending on the UUIDs that are discovered, this function should forward the events
     *          to their respective service instances.
     *
     * @param[in] p_event  Pointer to the database discovery event.
     */
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        ble_cts_c_on_db_disc_evt(&m_cts_c, p_evt);
    }
    
    
    /**@brief Function for putting the chip into sleep mode.
     *
     * @note This function will not return.
     */
    static void sleep_mode_enter(void)
    {
        ret_code_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    
        // Prepare wakeup buttons.
        err_code = bsp_btn_ble_sleep_mode_prepare();
        APP_ERROR_CHECK(err_code);
    
        // Go to system-off mode (this function will not return; wakeup will cause a reset).
        err_code = sd_power_system_off();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling advertising events.
     *
     * @details This function will be called for advertising events which are passed to the application.
     *
     * @param[in] ble_adv_evt  Advertising event.
     */
    static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
    {
        ret_code_t err_code;
    
        switch (ble_adv_evt)
        {
            case BLE_ADV_EVT_FAST:
                NRF_LOG_INFO("Fast advertising");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_SLOW:
                NRF_LOG_INFO("Slow advertising");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_SLOW);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_FAST_WHITELIST:
                NRF_LOG_INFO("Fast advertising with WhiteList");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_SLOW_WHITELIST:
                NRF_LOG_INFO("Slow advertising with WhiteList");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
                APP_ERROR_CHECK(err_code);
                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_IDLE:
                sleep_mode_enter();
                break;
    
            case BLE_ADV_EVT_WHITELIST_REQUEST:
            {
                ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
                ble_gap_irk_t  whitelist_irks[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
                uint32_t       addr_cnt = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
                uint32_t       irk_cnt  = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
                err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt,
                                            whitelist_irks,  &irk_cnt);
                APP_ERROR_CHECK(err_code);
                NRF_LOG_DEBUG("pm_whitelist_get returns %d addr in whitelist and %d irk whitelist",
                               addr_cnt,
                               irk_cnt);
    
                // Apply the whitelist.
                err_code = ble_advertising_whitelist_reply(&m_advertising,
                                                           whitelist_addrs,
                                                           addr_cnt,
                                                           whitelist_irks,
                                                           irk_cnt);
                APP_ERROR_CHECK(err_code);
            }
            break;
    
            default:
                break;
        }
    }
    
    
    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code;
    
        pm_handler_secure_on_connection(p_ble_evt);
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                NRF_LOG_INFO("Connected.");
                err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                APP_ERROR_CHECK(err_code);
                m_cur_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_cur_conn_handle);
                APP_ERROR_CHECK(err_code);
    
                NRF_LOG_INFO("ble_evt_handler connected -> fds_write_1.");
                fds_write_1();
    
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected.");
                m_cur_conn_handle = BLE_CONN_HANDLE_INVALID;
                if (p_ble_evt->evt.gap_evt.conn_handle == m_cts_c.conn_handle)
                {
                    m_cts_c.conn_handle = BLE_CONN_HANDLE_INVALID;
                }
                break; // BLE_GAP_EVT_DISCONNECTED
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("PHY update request.");
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTC_EVT_TIMEOUT:
                // Disconnect on GATT Client timeout event.
                NRF_LOG_DEBUG("GATT Client Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GATTS_EVT_TIMEOUT:
                // Disconnect on GATT Server timeout event.
                NRF_LOG_DEBUG("GATT Server Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief Function for handling events from the BSP module.
     *
     * @param[in]   event   Event generated by button press.
     */
    void bsp_event_handler(bsp_event_t event)
    {
        ret_code_t err_code;
    
        switch (event)
        {
            case BSP_EVENT_SLEEP:
                sleep_mode_enter();
                break;
    
            case BSP_EVENT_DISCONNECT:
                err_code = sd_ble_gap_disconnect(m_cur_conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
                break;
    
            case BSP_EVENT_WHITELIST_OFF:
                if (m_cts_c.conn_handle == BLE_CONN_HANDLE_INVALID)
                {
                    err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                    if (err_code != NRF_ERROR_INVALID_STATE)
                    {
                        APP_ERROR_CHECK(err_code);
                    }
                }
                break;
    
            case BSP_EVENT_KEY_0:
                if (m_cts_c.conn_handle != BLE_CONN_HANDLE_INVALID)
                {
                    err_code = ble_cts_c_current_time_read(&m_cts_c);
                    if (err_code == NRF_ERROR_NOT_FOUND)
                    {
                        NRF_LOG_INFO("Current Time Service is not discovered.");
                    }
                }
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief Function for initializing the BLE stack.
     *
     * @details Initializes the SoftDevice and the BLE event interrupt.
     */
    static void ble_stack_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    
    /**@brief Function for the Event Scheduler initialization.
     */
    static void scheduler_init(void)
    {
        APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
    }
    
    
    /**@brief Function for initializing buttons and leds.
     *
     * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
     */
    static void buttons_leds_init(bool * p_erase_bonds)
    {
        ret_code_t err_code;
        bsp_event_t startup_event;
    
        err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_btn_ble_init(NULL, &startup_event);
        APP_ERROR_CHECK(err_code);
    
        *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
    }
    
    
    /**@brief Function for the Peer Manager initialization.
     */
    static void peer_manager_init(void)
    {
        ble_gap_sec_params_t sec_param;
        ret_code_t           err_code;
    
        err_code = pm_init();
        APP_ERROR_CHECK(err_code);
    
        memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
    
        // Security parameters to be used for all security procedures.
        sec_param.bond           = SEC_PARAM_BOND;
        sec_param.mitm           = SEC_PARAM_MITM;
        sec_param.lesc           = SEC_PARAM_LESC;
        sec_param.keypress       = SEC_PARAM_KEYPRESS;
        sec_param.io_caps        = SEC_PARAM_IO_CAPABILITIES;
        sec_param.oob            = SEC_PARAM_OOB;
        sec_param.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;
        sec_param.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;
        sec_param.kdist_own.enc  = 1;
        sec_param.kdist_own.id   = 1;
        sec_param.kdist_peer.enc = 1;
        sec_param.kdist_peer.id  = 1;
    
        err_code = pm_sec_params_set(&sec_param);
        APP_ERROR_CHECK(err_code);
    
        err_code = pm_register(pm_evt_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the advertising functionality.
     *
     * @details Encodes the required advertising data and passes it to the stack.
     *          Also builds a structure to be passed to the stack when starting advertising.
     */
    static void advertising_init()
    {
        ret_code_t             err_code;
        ble_advertising_init_t init;
    
        memset(&init, 0, sizeof(init));
    
        init.advdata.name_type                = BLE_ADVDATA_FULL_NAME;
        init.advdata.include_appearance       = true;
        init.advdata.flags                    = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
        init.advdata.uuids_solicited.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
        init.advdata.uuids_solicited.p_uuids  = m_adv_uuids;
    
        init.config.ble_adv_whitelist_enabled = true;
        init.config.ble_adv_fast_enabled      = true;
        init.config.ble_adv_fast_interval     = APP_ADV_FAST_INTERVAL;
        init.config.ble_adv_fast_timeout      = APP_ADV_FAST_DURATION;
        init.config.ble_adv_slow_enabled      = true;
        init.config.ble_adv_slow_interval     = APP_ADV_SLOW_INTERVAL;
        init.config.ble_adv_slow_timeout      = APP_ADV_SLOW_DURATION;
    
        init.evt_handler = on_adv_evt;
    
        err_code = ble_advertising_init(&m_advertising, &init);
        APP_ERROR_CHECK(err_code);
    
        ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
    }
    
    
    /**
     * @brief Database discovery collector initialization.
     */
    static void db_discovery_init(void)
    {
        ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    /**@brief Function for initializing power management.
     */
    static void power_management_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the idle state (main loop).
     *
     * @details If there is no pending log operation, then sleep until next the next event occurs.
     */
    static void idle_state_handle(void)
    {
        app_sched_execute();
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        bool erase_bonds;
    
        // Initialize.
        nrf_cal_init();
        log_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        scheduler_init();
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        db_discovery_init();
        advertising_init();
        peer_manager_init();
        services_init();
        conn_params_init();
    
        // Start execution.
        NRF_LOG_INFO("Current Time service client started.");
    
        advertising_start(erase_bonds);
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
        }
    }
    
    
    /**
     * @}
     */
    

    ble_app_cts_c_calendar-1.zip

Reply
  • I had been using WRITE_SIZE 1024 from another suggestion on devzone, but still the same issue.
    The other bit of code merged was the Calendar example,
    and it seems the function nrf_cal_set_callback() is what seems to be causing the Assert.
    Without the callback(), the fds_record_write() is working ok.
    I checked the suggestion by Torbjørn (ovrebekk), to make sure RTC2 is being used, and it is.

    I merged sdk 15.3 CTS with Calendar and added the FDS write() to test on DK832 and reproduce the issue.
    The fault happens in fds_write_1() during fds_record_write(), line 248 on SES.
    (After connecting on nRF Connect, press button 1 on the DK).

    thank-you,

    <00> info>�app:�Current�Time�service�client�started.
    00> 
    <00> debug>�app:�pm_whitelist_get�returns�1�addr�in�whitelist�and�1�irk�whitelist
    00> 
    <00> info>�app:�Fast�advertising�with�WhiteList
    00> 
    00> bme280_read_3�top
    00> fds_write_1�mid�1
    00> fds_write_1�mid�2
    00> rec_id sample1 sample2 sample3 sample4
    00> C �1 �2 �3 �4 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x10
    00> 
    <00> info>�app:�Connected.
    00> 
    <00> info>�app:�ble_evt_handler�connected�->�fds_write_1.
    00> 
    <00> debug>�nrf_ble_gatt:�Peer�on�connection�0x0�requested�a�data�length�of�27�bytes.
    00> 
    <00> debug>�nrf_ble_gatt:�Updating�data�length�to�27�on�connection�0x0.
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x23
    00> 
    <00> debug>�nrf_ble_gatt:�Data�length�updated�to�27�on�connection�0x0.
    00> 
    <00> debug>�nrf_ble_gatt:�max_rx_octets:�27
    00> 
    <00> debug>�nrf_ble_gatt:�max_tx_octets:�27
    00> 
    <00> debug>�nrf_ble_gatt:�max_rx_time:�328
    00> 
    <00> debug>�nrf_ble_gatt:�max_tx_time:�2120
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x24
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x14
    00> 
    <00> info>�peer_manager_handler:�Connection�secured:�role:�Peripheral,�conn_handle:�0,�procedure:�Encryption
    00> 
    <00> debug>�ble_db_disc:�Starting�discovery�of�service�with�UUID�0x1805�on�connection�handle�0x0.
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x1A
    00> 
    <00> debug>�ble_db_disc:�Found�service�UUID�0x1805.
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x30
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x32
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x32
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x33
    00> 
    <00> debug>�ble_db_disc:�Discovery�of�service�with�UUID�0x1805�completed�with�success�on�connection�handle�0x0.
    00> 
    <00> debug>�ble_cts_c:�Database�Discovery�handler�called�with�event�0x0
    00> 
    <00> info>�ble_cts_c:�Current�Time�Service�discovered�at�peer.
    00> 
    <00> info>�app:�Current�Time�Service�discovered�on�server.
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x33
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x12
    00> 
    <00> debug>�ble_cts_c:�BLE�event�handler�called�with�event�0x36
    00> 
    <00> debug>�ble_cts_c:�Current�Time�read�response�data:
    00> 
    <00> debug>�ble_cts_c:��E4�07�0B�13�15�10�32�04|......2.
    00> 
    <00> debug>�ble_cts_c:��C5�00������������������|..������
    00> 
    <00> info>�app:�Current�Time�received.
    00> 
    00> Epoch:�1605820643
    00> New�time:�11/19/20�-�21:17:18
    00> bme280_read_3�top
    00> fds_write_1�mid�1
    

    /**
     * Copyright (c) 2014 - 2019, 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.
     *
     */
    /** @file
     *
     * @defgroup ble_sdk_app_cts_c_main main.c
     * @{
     * @ingroup ble_sdk_app_cts_c
     * @brief Current Time Profile sample application.
     *
     * This file contains the source code for a sample application that uses Current Time Service.
     * This is the client role of the profile, implemented on a peripheral device.
     * When a central device connects, the application will trigger a security procedure (if this is not done
     * by the central side first). Completion of the security procedure will trigger a service
     * discovery. When the Current Time Service and Characteristic have been discovered on the
     * server, pressing button 1 will trigger a read of the current time and print it on the UART.
     *
     */
    
    /** ADD TO CTS
    
    #define NRF_LOG_DEFERRED 1
    #define NRF_LOG_DEFAULT_LEVEL 4
    DEBUG
    
    #include <stdio.h>
    #include "nrf_calendar.h"
    static bool run_time_updates = true;
    
    
    #include "SEGGER_RTT.h"
    #include "SEGGER_RTT_Conf.h"
    
    */
    
    
    #include <stdint.h>
    #include <string.h>
    #include "nrf.h"
    #include "app_error.h"
    #include "app_scheduler.h"
    #include "app_timer.h"
    #include "ble.h"
    #include "ble_cts_c.h"
    #include "ble_db_discovery.h"
    #include "ble_hci.h"
    #include "ble_srv_common.h"
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_conn_params.h"
    #include "bsp_btn_ble.h"
    #include "peer_manager.h"
    #include "peer_manager_handler.h"
    #include "nordic_common.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_soc.h"
    #include "nrf_sdh_ble.h"
    #include "fds.h"
    #include "ble_conn_state.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_ble_qwr.h"
    #include "nrf_pwr_mgmt.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    /* for Calendar: */
    #include <stdio.h>
    #include "nrf_calendar.h"
    static bool run_time_updates = true;
    
    #include "SEGGER_RTT.h"
    #include "SEGGER_RTT_Conf.h"
    
    
    #define DEVICE_NAME                     "Nordic_CTS"                                /**< Name of the device. Will be included in the advertising data. */
    
    #define APP_BLE_OBSERVER_PRIO           3                                           /**< Application's BLE observer priority. You shouldn't need to modify this value. */
    #define APP_BLE_CONN_CFG_TAG            1                                           /**< A tag identifying the SoftDevice BLE configuration. */
    
    #define APP_ADV_FAST_INTERVAL           0x0028                                      /**< Fast advertising interval (in units of 0.625 ms). The default value corresponds to 25 ms. */
    #define APP_ADV_SLOW_INTERVAL           0x0C80                                      /**< Slow advertising interval (in units of 0.625 ms). The default value corresponds to 2 seconds. */
    
    #define APP_ADV_FAST_DURATION           3000                                        /**< The advertising duration of fast advertising in units of 10 milliseconds. */
    #define APP_ADV_SLOW_DURATION           18000                                       /**< The advertising duration of slow advertising in units of 10 milliseconds. */
    
    
    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(500, UNIT_1_25_MS)            /**< Minimum acceptable connection interval (0.5 seconds). */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(1000, UNIT_1_25_MS)           /**< Maximum acceptable connection interval (1 second). */
    #define SLAVE_LATENCY                   0                                           /**< Slave latency. */
    #define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)             /**< Connection supervisory time-out (4 seconds). */
    #define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000)                       /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
    #define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000)                      /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
    #define MAX_CONN_PARAMS_UPDATE_COUNT    3                                           /**< Number of attempts before giving up the connection parameter negotiation. */
    
    #define SEC_PARAM_TIMEOUT               30                                          /**< Time-out for pairing request or security request (in seconds). */
    #define SEC_PARAM_BOND                  1                                           /**< Perform bonding. */
    #define SEC_PARAM_MITM                  0                                           /**< Man In The Middle protection requirement. */
    #define SEC_PARAM_LESC                  0                                           /**< LE Secure Connections not enabled. */
    #define SEC_PARAM_KEYPRESS              0                                           /**< Keypress notifications not enabled. */
    #define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_NONE                        /**< I/O capabilities. */
    #define SEC_PARAM_OOB                   0                                           /**< Out Of Band data availability. */
    #define SEC_PARAM_MIN_KEY_SIZE          7                                           /**< Minimum encryption key size. */
    #define SEC_PARAM_MAX_KEY_SIZE          16                                          /**< Maximum encryption key size. */
    
    #define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE                   /**< Maximum size of scheduler events. Note that scheduler BLE stack events do not contain any data, as the events are being pulled from the stack in the event handler. */
    #ifdef SVCALL_AS_NORMAL_FUNCTION
    #define SCHED_QUEUE_SIZE                20                                          /**< Maximum number of events in the scheduler queue. More is needed in case of Serialization. */
    #else
    #define SCHED_QUEUE_SIZE                10                                          /**< Maximum number of events in the scheduler queue. */
    #endif
    
    #define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    
    BLE_CTS_C_DEF(m_cts_c);                                                             /**< Current Time service instance. */
    NRF_BLE_GATT_DEF(m_gatt);                                                           /**< GATT module instance. */
    NRF_BLE_QWR_DEF(m_qwr);                                                             /**< Context for the Queued Write module.*/
    BLE_ADVERTISING_DEF(m_advertising);                                                 /**< Advertising module instance. */
    BLE_DB_DISCOVERY_DEF(m_ble_db_discovery);                                           /**< DB discovery module instance. */
    
    static pm_peer_id_t m_peer_id;                                                      /**< Device reference handle to the current bonded central. */
    static uint16_t     m_cur_conn_handle = BLE_CONN_HANDLE_INVALID;                    /**< Handle of the current connection. */
    
    static pm_peer_id_t m_whitelist_peers[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];            /**< List of peers currently in the whitelist. */
    static uint32_t     m_whitelist_peer_cnt;                                           /**< Number of peers currently in the whitelist. */
    
    static ble_uuid_t m_adv_uuids[] = {{BLE_UUID_CURRENT_TIME_SERVICE, BLE_UUID_TYPE_BLE}};
    
    static char const * day_of_week[] =
    {
        "Unknown",
        "Monday",
        "Tuesday",
        "Wednesday",
        "Thursday",
        "Friday",
        "Saturday",
        "Sunday"
    };
    
    static char const * month_of_year[] =
    {
        "Unknown",
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
    };
    
    
    //***** fds_write_1 ***** START
    
    #define FILE_ID     0x1111
    #define REC_KEY     0x1111
    
    typedef struct
    {
        uint32_t sample1;
        uint32_t sample2;
        uint32_t sample3;
        uint32_t sample4;
    } sensor_data;
    
    /* Dummy configuration data. */
    static sensor_data sensor_data_sample =
    {
        .sample1  = 0,
        .sample2  = 0,
        .sample3  = 0,
        .sample4  = 0,
    };
    
    /* A record containing dummy configuration data. */
    static fds_record_t const sensor_data_record =
    {
        .file_id           = FILE_ID,
        .key               = REC_KEY,
        .data.p_data       = &sensor_data_sample,
        .data.length_words = (sizeof(sensor_data_sample) + 3) / sizeof(uint32_t),
    };
    
    /**@brief   Wait for fds to initialize. */
    static void fds_write_1(void)
    {
        uint32_t err_code;   
        uint32_t *data;
    
        ret_code_t rc;
        fds_record_desc_t   record_desc;
    
    //    NRF_LOG_INFO("fds_write_1 top\r\n");
        SEGGER_RTT_printf(0,"bme280_read_3 top\r\n");
    
        sensor_data_sample.sample1 = 0x00000001;
        sensor_data_sample.sample2 = 0x00000002;
        sensor_data_sample.sample3 = 0x00000003;
        sensor_data_sample.sample4 = 0x00000004;
    
    //    NRF_LOG_INFO("fds_write_1 mid 1\r\n");
        SEGGER_RTT_printf(0,"fds_write_1 mid 1\r\n");
    
        rc = fds_record_write(&record_desc, &sensor_data_record);
    
    //    NRF_LOG_INFO("fds_write_1 mid 2\r\n");
        SEGGER_RTT_printf(0,"fds_write_1 mid 2\r\n");
    
        if (rc != NRF_SUCCESS)
        {
            /* Handle error. */
    //          NRF_LOG_INFO("fds_write_1 Record not write.\r\n");
              SEGGER_RTT_printf(0,"fds_write_5 Record not write.\r\n");
        }
        else
        {
          data = (uint32_t *) sensor_data_record.data.p_data;
    
    //      NRF_LOG_INFO("rec_id\tsample1\tsample2\tsample3\tsample4\r\n");
    //      NRF_LOG_INFO("%x\t\t %x\t %x\t %x\t %x\t\r\n", record_desc.record_id, data[0], data[1], data[2], data[3]);
          SEGGER_RTT_printf(0,"rec_id\tsample1\tsample2\tsample3\tsample4\r\n");
          SEGGER_RTT_printf(0,"%x\t\t %x\t %x\t %x\t %x\t\r\n", record_desc.record_id, data[0], data[1], data[2], data[3]);
        }
    }
    
    //***** fds_write_1 ***** END
    
    
    /**@brief Callback function for asserts in the SoftDevice.
     *
     * @details This function will be called in case of an assert in the SoftDevice.
     *
     * @warning This handler is an example only and does not fit a final product. You need to analyze
     *          how your product is supposed to react in case of Assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in] line_num  Line number of the failing ASSERT call.
     * @param[in] file_name File name of the failing ASSERT call.
     */
    void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    {
        app_error_handler(DEAD_BEEF, line_num, p_file_name);
    }
    
    
    /**@brief Fetch the list of peer manager peer IDs.
     *
     * @param[inout] p_peers   The buffer where to store the list of peer IDs.
     * @param[inout] p_size    In: The size of the @p p_peers buffer.
     *                         Out: The number of peers copied in the buffer.
     */
    static void peer_list_get(pm_peer_id_t * p_peers, uint32_t * p_size)
    {
        pm_peer_id_t peer_id;
        uint32_t     peers_to_copy;
    
        peers_to_copy = (*p_size < BLE_GAP_WHITELIST_ADDR_MAX_COUNT) ?
                         *p_size : BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
        peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
        *p_size = 0;
    
        while ((peer_id != PM_PEER_ID_INVALID) && (peers_to_copy--))
        {
            p_peers[(*p_size)++] = peer_id;
            peer_id = pm_next_peer_id_get(peer_id);
        }
    }
    
    
    /**@brief Clear bond information from persistent storage.
     */
    static void delete_bonds(void)
    {
        ret_code_t err_code;
    
        NRF_LOG_INFO("Erase bonds!");
    
        err_code = pm_peers_delete();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for starting advertising.
     */
    static void advertising_start(bool erase_bonds)
    {
        if (erase_bonds == true)
        {
            delete_bonds();
            // Advertising is started by PM_EVT_PEERS_DELETE_SUCCEEDED event.
        }
        else
        {
            ret_code_t ret;
    
            memset(m_whitelist_peers, PM_PEER_ID_INVALID, sizeof(m_whitelist_peers));
            m_whitelist_peer_cnt = (sizeof(m_whitelist_peers) / sizeof(pm_peer_id_t));
    
            peer_list_get(m_whitelist_peers, &m_whitelist_peer_cnt);
    
            ret = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt);
            APP_ERROR_CHECK(ret);
    
            // Setup the device identies list.
            // Some SoftDevices do not support this feature.
            ret = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt);
            if (ret != NRF_ERROR_NOT_SUPPORTED)
            {
                APP_ERROR_CHECK(ret);
            }
    
            ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
            APP_ERROR_CHECK(ret);
        }
    }
    
    
    /**@brief Function for handling Peer Manager events.
     *
     * @param[in] p_evt  Peer Manager event.
     */
    static void pm_evt_handler(pm_evt_t const * p_evt)
    {
        ret_code_t err_code;
    
        pm_handler_on_pm_evt(p_evt);
        pm_handler_flash_clean(p_evt);
    
        switch (p_evt->evt_id)
        {
            case PM_EVT_CONN_SEC_SUCCEEDED:
            {
                m_peer_id = p_evt->peer_id;
    
                // Discover peer's services.
                err_code  = ble_db_discovery_start(&m_ble_db_discovery, p_evt->conn_handle);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case PM_EVT_PEERS_DELETE_SUCCEEDED:
            {
                advertising_start(false);
            } break;
    
            case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
            {
                // Note: You should check on what kind of white list policy your application should use.
                if (     p_evt->params.peer_data_update_succeeded.flash_changed
                     && (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_BONDING))
                {
                    NRF_LOG_DEBUG("New Bond, add the peer to the whitelist if possible");
                    NRF_LOG_DEBUG("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d",
                                   m_whitelist_peer_cnt + 1,
                                   BLE_GAP_WHITELIST_ADDR_MAX_COUNT);
    
                    if (m_whitelist_peer_cnt < BLE_GAP_WHITELIST_ADDR_MAX_COUNT)
                    {
                        // Bonded to a new peer, add it to the whitelist.
                        m_whitelist_peers[m_whitelist_peer_cnt++] = m_peer_id;
    
                        // The whitelist has been modified, update it in the Peer Manager.
                        err_code = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt);
                        if (err_code != NRF_ERROR_NOT_SUPPORTED)
                        {
                            APP_ERROR_CHECK(err_code);
                        }
    
                        err_code = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt);
                        APP_ERROR_CHECK(err_code);
                    }
                }
            } break;
    
            default:
                break;
        }
    }
    
    void print_current_time()
    {
        printf("Epoch:\t%d\r\n", nrf_cal_get_epoch());
        printf("New time:\t%s\r\n", nrf_cal_get_time_string(false));
    }
    
    /* set run_time_updates=false to stop calendar updates*/
    void calendar_updated()
    {
        if(run_time_updates)
        {
    //        print_current_time();
    
            fds_write_1();
    
        }
    }
    
    
    
    /**@brief Function for handling the Current Time Service errors.
     *
     * @param[in]  nrf_error  Error code containing information about what went wrong.
     */
    static void current_time_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for handling the Current Time Service errors.
     *
     * @param[in] p_evt  Event received from the Current Time Service client.
     */
    static void current_time_print(ble_cts_c_evt_t * p_evt)
    {
    //    NRF_LOG_INFO("\r\nCurrent Time:");
    //    NRF_LOG_INFO("\r\nDate:");
    //
    //    NRF_LOG_INFO("\tDay of week   %s", (uint32_t)day_of_week[p_evt->
    //                                                         params.
    //                                                         current_time.
    //                                                         exact_time_256.
    //                                                         day_date_time.
    //                                                         day_of_week]);
    //
    //    if (p_evt->params.current_time.exact_time_256.day_date_time.date_time.day == 0)
    //    {
    //        NRF_LOG_INFO("\tDay of month  Unknown");
    //    }
    //    else
    //    {
    //        NRF_LOG_INFO("\tDay of month  %i",
    //                       p_evt->params.current_time.exact_time_256.day_date_time.date_time.day);
    //    }
    //
    //    NRF_LOG_INFO("\tMonth of year %s",
    //    (uint32_t)month_of_year[p_evt->params.current_time.exact_time_256.day_date_time.date_time.month]);
    //    if (p_evt->params.current_time.exact_time_256.day_date_time.date_time.year == 0)
    //    {
    //        NRF_LOG_INFO("\tYear          Unknown");
    //    }
    //    else
    //    {
    //        NRF_LOG_INFO("\tYear          %i",
    //                       p_evt->params.current_time.exact_time_256.day_date_time.date_time.year);
    //    }
    //    NRF_LOG_INFO("\r\nTime:");
    //    NRF_LOG_INFO("\tHours     %i",
    //                   p_evt->params.current_time.exact_time_256.day_date_time.date_time.hours);
    //    NRF_LOG_INFO("\tMinutes   %i",
    //                   p_evt->params.current_time.exact_time_256.day_date_time.date_time.minutes);
    //    NRF_LOG_INFO("\tSeconds   %i",
    //                   p_evt->params.current_time.exact_time_256.day_date_time.date_time.seconds);
    //    NRF_LOG_INFO("\tFractions %i/256 of a second",
    //                   p_evt->params.current_time.exact_time_256.fractions256);
    //
    //    NRF_LOG_INFO("\r\nAdjust reason:\r");
    //    NRF_LOG_INFO("\tDaylight savings %x",
    //                   p_evt->params.current_time.adjust_reason.change_of_daylight_savings_time);
    //    NRF_LOG_INFO("\tTime zone        %x",
    //                   p_evt->params.current_time.adjust_reason.change_of_time_zone);
    //    NRF_LOG_INFO("\tExternal update  %x",
    //                   p_evt->params.current_time.adjust_reason.external_reference_time_update);
    //    NRF_LOG_INFO("\tManual update    %x",
    //                   p_evt->params.current_time.adjust_reason.manual_time_update);
    
        uint32_t year, month, day, hour, minute, second;
    
        /* time received from cts populates variables */
        year = p_evt->params.current_time.exact_time_256.day_date_time.date_time.year;
        month = p_evt->params.current_time.exact_time_256.day_date_time.date_time.month;
        day = p_evt->params.current_time.exact_time_256.day_date_time.date_time.day;
        hour = p_evt->params.current_time.exact_time_256.day_date_time.date_time.hours;
        minute = p_evt->params.current_time.exact_time_256.day_date_time.date_time.minutes;
        second = p_evt->params.current_time.exact_time_256.day_date_time.date_time.seconds;
    
        /* variables from cts set calendar */
        nrf_cal_set_time(year, month, day, hour, minute, second);
    
        /* function calendar_updated called every 5 seconds */
        nrf_cal_set_callback(calendar_updated, 5);
    
    
    
    }
    
    
    /**@brief Function for the timer initialization.
     *
     * @details Initializes the timer module.
     */
    static void timers_init(void)
    {
        ret_code_t err_code;
    
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the Current Time Service client events.
     *
     * @details This function will be called for all events in the Current Time Service client that
     *          are passed to the application.
     *
     * @param[in] p_evt Event received from the Current Time Service client.
     */
    static void on_cts_c_evt(ble_cts_c_t * p_cts, ble_cts_c_evt_t * p_evt)
    {
        ret_code_t err_code;
    
        switch (p_evt->evt_type)
        {
            case BLE_CTS_C_EVT_DISCOVERY_COMPLETE:
                NRF_LOG_INFO("Current Time Service discovered on server.");
                err_code = ble_cts_c_handles_assign(&m_cts_c,
                                                    p_evt->conn_handle,
                                                    &p_evt->params.char_handles);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_CTS_C_EVT_DISCOVERY_FAILED:
                NRF_LOG_INFO("Current Time Service not found on server. ");
                // CTS not found in this case we just disconnect. There is no reason to stay
                // in the connection for this simple app since it all wants is to interact with CT
                if (p_evt->conn_handle != BLE_CONN_HANDLE_INVALID)
                {
                    err_code = sd_ble_gap_disconnect(p_evt->conn_handle,
                                                     BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                    APP_ERROR_CHECK(err_code);
                }
                break;
    
            case BLE_CTS_C_EVT_DISCONN_COMPLETE:
                NRF_LOG_INFO("Disconnect Complete.");
                break;
    
            case BLE_CTS_C_EVT_CURRENT_TIME:
                NRF_LOG_INFO("Current Time received.");
                current_time_print(p_evt);
    
    //            NRF_LOG_INFO("on_cts_c_evt current_time_print-> fds_write_1.");
    //            fds_write_1();
    
                break;
    
            case BLE_CTS_C_EVT_INVALID_TIME:
                NRF_LOG_INFO("Invalid Time received.");
                break;
    
            default:
                break;
        }
    }
    
    
    /**@brief Function for the GAP initialization.
     *
     * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
     *          device including the device name, appearance, and the preferred connection parameters.
     */
    static void gap_params_init(void)
    {
        ret_code_t              err_code;
        ble_gap_conn_params_t   gap_conn_params;
        ble_gap_conn_sec_mode_t sec_mode;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    
        err_code = sd_ble_gap_device_name_set(&sec_mode,
                                              (const uint8_t *)DEVICE_NAME,
                                              strlen(DEVICE_NAME));
        APP_ERROR_CHECK(err_code);
    
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));
    
        gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
        gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
        gap_conn_params.slave_latency     = SLAVE_LATENCY;
        gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;
    
        err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the GATT module.
     */
    static void gatt_init(void)
    {
        ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling Queued Write Module errors.
     *
     * @details A pointer to this function will be passed to each service which may need to inform the
     *          application about an error.
     *
     * @param[in]   nrf_error   Error code containing information about what went wrong.
     */
    static void nrf_qwr_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for initializing services that will be used by the application.
     */
    static void services_init(void)
    {
        ret_code_t         err_code;
        ble_cts_c_init_t   cts_init = {0};
        nrf_ble_qwr_init_t qwr_init = {0};
    
        // Initialize Queued Write Module.
        qwr_init.error_handler = nrf_qwr_error_handler;
    
        err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
        APP_ERROR_CHECK(err_code);
    
        // Initialize CTS.
        cts_init.evt_handler   = on_cts_c_evt;
        cts_init.error_handler = current_time_error_handler;
        err_code               = ble_cts_c_init(&m_cts_c, &cts_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the Connection Parameters module.
     *
     * @details This function will be called for all events in the Connection Parameters module that
     *          are passed to the application.
     *          @note All this function does is to disconnect. This could have been done by simply
     *                setting the disconnect_on_fail config parameter, but instead we use the event
     *                handler mechanism to demonstrate its use.
     *
     * @param[in] p_evt  Event received from the Connection Parameters module.
     */
    static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
    {
        ret_code_t err_code;
    
        if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
        {
            err_code = sd_ble_gap_disconnect(m_cur_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    
    /**@brief Function for handling a Connection Parameters error.
     *
     * @param[in]   nrf_error   Error code containing information about what went wrong.
     */
    static void conn_params_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for initializing the Connection Parameters module.
     */
    static void conn_params_init(void)
    {
        ret_code_t             err_code;
        ble_conn_params_init_t cp_init;
    
        memset(&cp_init, 0, sizeof(cp_init));
    
        cp_init.p_conn_params                  = NULL;
        cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
        cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
        cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
        cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
        cp_init.disconnect_on_fail             = false;
        cp_init.evt_handler                    = on_conn_params_evt;
        cp_init.error_handler                  = conn_params_error_handler;
    
        err_code = ble_conn_params_init(&cp_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling Database Discovery events.
     *
     * @details This function is a callback function to handle events from the database discovery module.
     *          Depending on the UUIDs that are discovered, this function should forward the events
     *          to their respective service instances.
     *
     * @param[in] p_event  Pointer to the database discovery event.
     */
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        ble_cts_c_on_db_disc_evt(&m_cts_c, p_evt);
    }
    
    
    /**@brief Function for putting the chip into sleep mode.
     *
     * @note This function will not return.
     */
    static void sleep_mode_enter(void)
    {
        ret_code_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    
        // Prepare wakeup buttons.
        err_code = bsp_btn_ble_sleep_mode_prepare();
        APP_ERROR_CHECK(err_code);
    
        // Go to system-off mode (this function will not return; wakeup will cause a reset).
        err_code = sd_power_system_off();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling advertising events.
     *
     * @details This function will be called for advertising events which are passed to the application.
     *
     * @param[in] ble_adv_evt  Advertising event.
     */
    static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
    {
        ret_code_t err_code;
    
        switch (ble_adv_evt)
        {
            case BLE_ADV_EVT_FAST:
                NRF_LOG_INFO("Fast advertising");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_SLOW:
                NRF_LOG_INFO("Slow advertising");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_SLOW);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_FAST_WHITELIST:
                NRF_LOG_INFO("Fast advertising with WhiteList");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_SLOW_WHITELIST:
                NRF_LOG_INFO("Slow advertising with WhiteList");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
                APP_ERROR_CHECK(err_code);
                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_IDLE:
                sleep_mode_enter();
                break;
    
            case BLE_ADV_EVT_WHITELIST_REQUEST:
            {
                ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
                ble_gap_irk_t  whitelist_irks[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
                uint32_t       addr_cnt = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
                uint32_t       irk_cnt  = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
                err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt,
                                            whitelist_irks,  &irk_cnt);
                APP_ERROR_CHECK(err_code);
                NRF_LOG_DEBUG("pm_whitelist_get returns %d addr in whitelist and %d irk whitelist",
                               addr_cnt,
                               irk_cnt);
    
                // Apply the whitelist.
                err_code = ble_advertising_whitelist_reply(&m_advertising,
                                                           whitelist_addrs,
                                                           addr_cnt,
                                                           whitelist_irks,
                                                           irk_cnt);
                APP_ERROR_CHECK(err_code);
            }
            break;
    
            default:
                break;
        }
    }
    
    
    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code;
    
        pm_handler_secure_on_connection(p_ble_evt);
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                NRF_LOG_INFO("Connected.");
                err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                APP_ERROR_CHECK(err_code);
                m_cur_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_cur_conn_handle);
                APP_ERROR_CHECK(err_code);
    
                NRF_LOG_INFO("ble_evt_handler connected -> fds_write_1.");
                fds_write_1();
    
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected.");
                m_cur_conn_handle = BLE_CONN_HANDLE_INVALID;
                if (p_ble_evt->evt.gap_evt.conn_handle == m_cts_c.conn_handle)
                {
                    m_cts_c.conn_handle = BLE_CONN_HANDLE_INVALID;
                }
                break; // BLE_GAP_EVT_DISCONNECTED
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("PHY update request.");
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTC_EVT_TIMEOUT:
                // Disconnect on GATT Client timeout event.
                NRF_LOG_DEBUG("GATT Client Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GATTS_EVT_TIMEOUT:
                // Disconnect on GATT Server timeout event.
                NRF_LOG_DEBUG("GATT Server Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief Function for handling events from the BSP module.
     *
     * @param[in]   event   Event generated by button press.
     */
    void bsp_event_handler(bsp_event_t event)
    {
        ret_code_t err_code;
    
        switch (event)
        {
            case BSP_EVENT_SLEEP:
                sleep_mode_enter();
                break;
    
            case BSP_EVENT_DISCONNECT:
                err_code = sd_ble_gap_disconnect(m_cur_conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
                break;
    
            case BSP_EVENT_WHITELIST_OFF:
                if (m_cts_c.conn_handle == BLE_CONN_HANDLE_INVALID)
                {
                    err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                    if (err_code != NRF_ERROR_INVALID_STATE)
                    {
                        APP_ERROR_CHECK(err_code);
                    }
                }
                break;
    
            case BSP_EVENT_KEY_0:
                if (m_cts_c.conn_handle != BLE_CONN_HANDLE_INVALID)
                {
                    err_code = ble_cts_c_current_time_read(&m_cts_c);
                    if (err_code == NRF_ERROR_NOT_FOUND)
                    {
                        NRF_LOG_INFO("Current Time Service is not discovered.");
                    }
                }
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief Function for initializing the BLE stack.
     *
     * @details Initializes the SoftDevice and the BLE event interrupt.
     */
    static void ble_stack_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    
    /**@brief Function for the Event Scheduler initialization.
     */
    static void scheduler_init(void)
    {
        APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
    }
    
    
    /**@brief Function for initializing buttons and leds.
     *
     * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
     */
    static void buttons_leds_init(bool * p_erase_bonds)
    {
        ret_code_t err_code;
        bsp_event_t startup_event;
    
        err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_btn_ble_init(NULL, &startup_event);
        APP_ERROR_CHECK(err_code);
    
        *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
    }
    
    
    /**@brief Function for the Peer Manager initialization.
     */
    static void peer_manager_init(void)
    {
        ble_gap_sec_params_t sec_param;
        ret_code_t           err_code;
    
        err_code = pm_init();
        APP_ERROR_CHECK(err_code);
    
        memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
    
        // Security parameters to be used for all security procedures.
        sec_param.bond           = SEC_PARAM_BOND;
        sec_param.mitm           = SEC_PARAM_MITM;
        sec_param.lesc           = SEC_PARAM_LESC;
        sec_param.keypress       = SEC_PARAM_KEYPRESS;
        sec_param.io_caps        = SEC_PARAM_IO_CAPABILITIES;
        sec_param.oob            = SEC_PARAM_OOB;
        sec_param.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;
        sec_param.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;
        sec_param.kdist_own.enc  = 1;
        sec_param.kdist_own.id   = 1;
        sec_param.kdist_peer.enc = 1;
        sec_param.kdist_peer.id  = 1;
    
        err_code = pm_sec_params_set(&sec_param);
        APP_ERROR_CHECK(err_code);
    
        err_code = pm_register(pm_evt_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the advertising functionality.
     *
     * @details Encodes the required advertising data and passes it to the stack.
     *          Also builds a structure to be passed to the stack when starting advertising.
     */
    static void advertising_init()
    {
        ret_code_t             err_code;
        ble_advertising_init_t init;
    
        memset(&init, 0, sizeof(init));
    
        init.advdata.name_type                = BLE_ADVDATA_FULL_NAME;
        init.advdata.include_appearance       = true;
        init.advdata.flags                    = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
        init.advdata.uuids_solicited.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
        init.advdata.uuids_solicited.p_uuids  = m_adv_uuids;
    
        init.config.ble_adv_whitelist_enabled = true;
        init.config.ble_adv_fast_enabled      = true;
        init.config.ble_adv_fast_interval     = APP_ADV_FAST_INTERVAL;
        init.config.ble_adv_fast_timeout      = APP_ADV_FAST_DURATION;
        init.config.ble_adv_slow_enabled      = true;
        init.config.ble_adv_slow_interval     = APP_ADV_SLOW_INTERVAL;
        init.config.ble_adv_slow_timeout      = APP_ADV_SLOW_DURATION;
    
        init.evt_handler = on_adv_evt;
    
        err_code = ble_advertising_init(&m_advertising, &init);
        APP_ERROR_CHECK(err_code);
    
        ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
    }
    
    
    /**
     * @brief Database discovery collector initialization.
     */
    static void db_discovery_init(void)
    {
        ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    /**@brief Function for initializing power management.
     */
    static void power_management_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the idle state (main loop).
     *
     * @details If there is no pending log operation, then sleep until next the next event occurs.
     */
    static void idle_state_handle(void)
    {
        app_sched_execute();
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        bool erase_bonds;
    
        // Initialize.
        nrf_cal_init();
        log_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        scheduler_init();
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        db_discovery_init();
        advertising_init();
        peer_manager_init();
        services_init();
        conn_params_init();
    
        // Start execution.
        NRF_LOG_INFO("Current Time service client started.");
    
        advertising_start(erase_bonds);
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
        }
    }
    
    
    /**
     * @}
     */
    

    ble_app_cts_c_calendar-1.zip

Children
No Data
Related