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

Multilink central adding advertising. Error 12 on advertising_start()

Hi. I have added advertising to my multilink central project SDK15.0. Running on a nRF52840.

I get a error 12 when advertising_start(); is called on startup. I believe this means adv packet is too big.

However I don't see how this could be the case, because I copied it from another example (NUS peripheral) which works ok.

One issue may be that this project is a central that is scanning, so advertising should be non-connectable only. Not sure how to do this. My main is below.

Any help would be appreciated.

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

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nordic_common.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "app_timer.h"
#include "bsp_btn_ble.h"
#include "ble.h"
#include "ble_hci.h"
#include "ble_advdata.h"
#include "ble_advertising.h"
#include "ble_conn_params.h"
#include "ble_db_discovery.h"
#include "ble_nus_c.h"
#include "ble_conn_state.h"
#include "nrf_ble_gatt.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_drv_power.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_queue.h"
#include "nrf_delay.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_pwm.h"
#include "nrf_drv_clock.h"
#include "nrf_drv_rtc.h"
#include "lcd_driver.h"
#include "BQ25896_driver.h"
#include "temp_lookup.h"
#include "nrf_sdh_soc.h"

#define setbit(var, bit)        ((var) |= (1 << (bit)))
#define clearbit(var, bit)      ((var) &= ~(1 << (bit)))

#define DEVICE_NAME                     "TEST1"
#define APP_COMPANY_IDENTIFIER          0x0059                                  /**< Company identifier for Nordic Semiconductor ASA. as per www.bluetooth.org. */
#define APP_ADV_INTERVAL                200                                          /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
#define APP_ADV_DURATION                18000                                       /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
#define MIN_CONN_INTERVAL               MSEC_TO_UNITS(75, UNIT_1_25_MS) //was 7.5            /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
#define MAX_CONN_INTERVAL               MSEC_TO_UNITS(100, UNIT_1_25_MS) //was 100            /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
#define SLAVE_LATENCY                   0                                           /**< Slave latency. */
#define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)             /**< Connection supervisory timeout (4 seconds), Supervision Timeout uses 10 ms units. */


#define APP_BLE_CONN_CFG_TAG      1                                     /**< A tag that refers to the BLE stack configuration we set with @ref sd_ble_cfg_set. Default tag is @ref APP_BLE_CONN_CFG_TAG. */
#define APP_BLE_OBSERVER_PRIO     3                                     /**< Application's BLE observer priority. You shouldn't need to modify this value. */

#define UART_TX_BUF_SIZE          256                                     /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE          256

#define NUS_SERVICE_UUID_TYPE     BLE_UUID_TYPE_VENDOR_BEGIN              /**< UUID type for the Nordic UART Service (vendor specific). */

#define BUTTON_DETECTION_DELAY    APP_TIMER_TICKS(50)                   /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */

#define LED_G                     21
#define LED_R                     17
#define LED_B                     19
#define PUSH_BUTTON               44 //P1.12
#define EN_PIN                    23
#define MAG_SENS                  5

#define COIL_EN                   22
#define COIL_PWM                  24
#define POWER_EN                  2
#define TRIAC_3                   7
#define TRIAC_2                   9
#define TRIAC_1                   47

#define STATE_START               0
#define STATE_ASLEEP              1
#define STATE_ACTIVE              2
#define STATE_CHARGING            3

#define SCAN_INTERVAL             0x0200//0x00A0                                /**< Determines scan interval in units of 0.625 millisecond. */
#define SCAN_WINDOW               0x0050//0x0050                               /**< Determines scan window in units of 0.625 millisecond. */
#define SCAN_DURATION             0x0000                                /**< Duration of the scanning in units of 10 milliseconds. If set to 0x0000, scanning will continue until it is explicitly disabled. */

#define MIN_CONNECTION_INTERVAL   MSEC_TO_UNITS(75, UNIT_1_25_MS) //was 7.5     /**< Determines minimum connection interval in milliseconds. */
#define MAX_CONNECTION_INTERVAL   MSEC_TO_UNITS(100, UNIT_1_25_MS)  //was 10     /**< Determines maximum connection interval in milliseconds. */
#define SLAVE_LATENCY             0                                     /**< Determines slave latency in terms of connection events. */
#define SUPERVISION_TIMEOUT       MSEC_TO_UNITS(4000, UNIT_10_MS)       /**< Determines supervision time-out in units of 10 milliseconds. */

#define COMPARE_COUNTERTIME  (1)                                        /**< Get Compare event COMPARE_TIME seconds after the counter starts from 0. */
#define BAND_ARRAY_SIZE             10
#define MAX_DOWNLOAD_ARRAY_SIZE     256

#define AGE_TIMEOUT  32  //8 ticks / s = 4s it will clear the peer_Address
//i.e. SB clearing download quicker than it transmitted from the peripheral x128 = 128,000 bytes

#define BOOTLOADER_DFU_START 0xB1

const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(2); /**< Declaring an instance of nrf_drv_rtc for RTC1. */

static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
// Declare variables holding PWM sequence values. In this example only one channel is used 
static nrf_pwm_values_individual_t seq_values[] = {0, 0, 0, 0};
static nrf_pwm_sequence_t const seq =
{
    .values.p_individual = seq_values,
    .length          = NRF_PWM_VALUES_LENGTH(seq_values),
    .repeats         = 0,
    .end_delay       = 0
};

static uint8_t pwm_triac_count = 0;
static uint8_t connection_peer[6];

static uint8_t display_count = 0;

static uint16_t output[3] = {0x0000,0x0000,0x0000};

static uint16_t size_to_read = 0;
static uint16_t NTC_1_ave = 8000;
static uint16_t NTC_2_ave = 8000;
static uint16_t Coil_current_ave = 8000;
static uint8_t responce_i2c = 0;
#define mov_ave_divisor 8

#define BAND_MESSAGE_SIZE 240
static uint8_t message_to_band[BAND_MESSAGE_SIZE * 4];

static band_status_t band_array[BAND_ARRAY_SIZE];

#define SAMPLES_IN_BUFFER 3
static nrf_saadc_value_t m_buffer[SAMPLES_IN_BUFFER];

static bool just_sent_download_data = false;
static uint16_t dp_count = 0;

static uint8_t packets_to_send = 0;

static uint8_t test_counter = 0;


static uint16_t chg_current = 0; //0x12
static uint16_t bat_voltage = 0; //0x0E
static uint16_t sys_voltage = 0; //0x0F
static uint16_t bus_voltage = 0; //0x11

static uint8_t reg_00 = 0;
static uint8_t reg_02 = 0;
static uint8_t reg_03 = 0;
static uint8_t reg_06 = 0;
static uint8_t reg_0b = 0;
static uint8_t reg_0c = 0;
static uint8_t reg_0d = 0;

static uint8_t current_state = 0;
static uint8_t shutdown_count = 0;

static bool PG_STAT = false; //power good bit
static uint8_t CHARGE_STATE = 0;
static uint16_t IINLIM = 0;
static uint16_t IDPM_LIM = 0;
static uint16_t ICHG = 0;
static uint16_t VINDPM = 0;

#define PWM_VALUE   320
static uint16_t test_pwm = 320;



APP_TIMER_DEF(adv_timer);

NRF_BLE_GATT_DEF(m_gatt);                                               /**< GATT module instance. */
//BLE_LBS_C_ARRAY_DEF(m_lbs_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);           /**< LED Button client instances. */
BLE_NUS_C_ARRAY_DEF(m_nus_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT); 
BLE_DB_DISCOVERY_ARRAY_DEF(m_db_disc, NRF_SDH_BLE_CENTRAL_LINK_COUNT);  /**< Database discovery module instances. */
BLE_ADVERTISING_DEF(m_advertising);
static ble_uuid_t m_adv_uuids[]          =                                          /**< Universally unique service identifier. */
{
    {BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}
};

static char const m_target_name[] = "SWTG1"; 

static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; /**< buffer where advertising reports will be stored by the SoftDevice. */

static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */

void do_dfu(void);
void pwm_update_duty_cycle(uint16_t);
void pwm_update(uint16_t freq);
void pwm_stop(void);

/**@brief Pointer to the buffer where advertising reports will be stored by the SoftDevice. */
static ble_data_t m_scan_buffer =
{
    m_scan_buffer_data,
    BLE_GAP_SCAN_BUFFER_MIN
};

/**@brief Scan parameters requested for scanning and connection. */
static ble_gap_scan_params_t const m_scan_params =
{
    .active   = 0,  //was 0
    .interval = SCAN_INTERVAL,
    .window   = SCAN_WINDOW,

    .timeout           = SCAN_DURATION,
    .scan_phys         = BLE_GAP_PHY_1MBPS,  //BLE_GAP_PHY_CODED
    .filter_policy     = BLE_GAP_SCAN_FP_ACCEPT_ALL,

};

/**@brief NUS uuid. */
static ble_uuid_t const m_nus_uuid =
{
    .uuid = BLE_UUID_NUS_SERVICE,
    .type = NUS_SERVICE_UUID_TYPE
};

/**@brief Connection parameters requested for connection. */
static ble_gap_conn_params_t const m_connection_param =
{
    (uint16_t)MIN_CONNECTION_INTERVAL,
    (uint16_t)MAX_CONNECTION_INTERVAL,
    (uint16_t)SLAVE_LATENCY,
    (uint16_t)SUPERVISION_TIMEOUT
};


void clocks_start( void )
{
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART = 1;

    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
}


#define DEFAULT_READ_SIZE 4 //Basic commands to dock
#define MAX_READ_SIZE 1000 


static char rx_message[256];
static bool m_send_flag = 0;


bool message_rxd = false;

bool display_toggle = false;

static void clear_LEDS()
{
    nrf_gpio_pin_clear(LED_R);
    nrf_gpio_pin_clear(LED_G);
    nrf_gpio_pin_clear(LED_B);
}

static void enter_active_mode()
{
    //TODO
}

static void enter_charging_mode()
{
    //TODO
}

static void enter_sleep_mode() //Turn most things off
{
    //TODO
}

static void charger_tasks()
{
    //TODO
}

/** @brief: Function for handling the RTC1 interrupts.
 * Triggered on TICK and COMPARE0 match.
 */
static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
    if (int_type == NRF_DRV_RTC_INT_COMPARE2)
    {
        if(current_state == STATE_START) nrf_gpio_pin_set(LED_B);
        else if(current_state == STATE_ACTIVE)
        {
            //TODO
        }
        else if(current_state == STATE_CHARGING) 
        {
            //TODO
        }
        else if(current_state == STATE_ASLEEP)
        {
            nrf_gpio_pin_toggle(LED_B);
        }

        charger_tasks();

/*
        if(display_toggle == false)
        {
            display_next(); //Show next image
            nrf_gpio_pin_set(EN_PIN); //Turn on LCD
            display_toggle = true;
        }
        else 
        {
            nrf_gpio_pin_clear(EN_PIN); //Turn off LCD
            display_toggle = false;
        }
        */

        nrf_drv_rtc_counter_clear(&rtc); 
        nrf_drv_rtc_int_enable(&rtc, NRF_RTC_INT_COMPARE2_MASK); 

/*
        //TODO
*/        

    }
    else if (int_type == NRF_DRV_RTC_INT_TICK)
    {
        //TODO
    }
}


/**@brief Function to handle 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] p_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(0xDEADBEEF, line_num, p_file_name);
}


/**@brief Function for the LEDs initialization.
 *
 * @details Initializes all LEDs used by the application.
 */
static void leds_button_init(void)
{
    nrf_gpio_cfg_output(LED_G);
    nrf_gpio_cfg_output(LED_R);
    nrf_gpio_cfg_output(LED_B);
    nrf_gpio_cfg_output(EN_PIN);

    nrf_gpio_cfg_output(TRIAC_3);
    nrf_gpio_cfg_output(TRIAC_2);
    nrf_gpio_cfg_output(TRIAC_1);
    nrf_gpio_cfg_output(COIL_EN);
    nrf_gpio_cfg_output(POWER_EN);

    nrf_gpio_pin_clear(EN_PIN);
    nrf_gpio_pin_clear(TRIAC_3);
    nrf_gpio_pin_clear(TRIAC_2);
    nrf_gpio_pin_clear(TRIAC_1);
    nrf_gpio_pin_clear(COIL_EN);
    nrf_gpio_pin_clear(POWER_EN);

    nrf_gpio_cfg_input(PUSH_BUTTON,NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_input(MAG_SENS,NRF_GPIO_PIN_PULLUP);
}


/**@brief Function to start scanning. */
static void scan_start(void)
{
    ret_code_t ret;

    (void) sd_ble_gap_scan_stop();

    ret = sd_ble_gap_scan_start(&m_scan_params, &m_scan_buffer);
    APP_ERROR_CHECK(ret);
}

/**@brief Callback handling NUS Client events.
 *
 * @details This function is called to notify the application of NUS client events.
 *
 * @param[in]   p_ble_nus_c   NUS Client Handle. This identifies the NUS client
 * @param[in]   p_ble_nus_evt Pointer to the NUS Client event.
 */

/**@snippet [Handling events from the ble_nus_c module] */
static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
{
    ret_code_t err_code;
    uint16_t i;

    switch (p_ble_nus_evt->evt_type)
    {
        case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
            NRF_LOG_INFO("NUS service discovered on conn_handle 0x%x", p_ble_nus_evt->conn_handle);
            err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
            APP_ERROR_CHECK(err_code);

            err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
            APP_ERROR_CHECK(err_code);
            //NRF_LOG_INFO("Connected to device with Nordic UART Service.");

            break;

        case BLE_NUS_C_EVT_NUS_TX_EVT:

            break;

        case BLE_NUS_C_EVT_DISCONNECTED:
            NRF_LOG_INFO("NUS service disconnected on conn_handle 0x%x", p_ble_nus_evt->conn_handle);

            break;
    }
}
/**@snippet [Handling events from the ble_nus_c module] */

/**@brief Function for the GAP initialization.
 *
 * @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
 *          the device. It also sets the permissions and appearance.
 */
static void gap_params_init(void)
{
    uint32_t                err_code;
    ble_gap_conn_params_t   gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;
    ble_gap_addr_t my_address;

    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);

//    sd_ble_gap_addr_get(&my_address);
//    memcpy(my_peer_address, my_address.addr, 6);

    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 handling the advertising report BLE event.
 *
 * @param[in] p_adv_report  Advertising report from the SoftDevice.
 */
static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
{
    ret_code_t err_code;

    if (ble_advdata_name_find(p_adv_report->data.p_data, p_adv_report->data.len, m_target_name))
    {
        //TODO
    }


//TODO - Not connecting at the moment
    if(memcmp(p_adv_report->peer_addr.addr,connection_peer,6)==0)
    {
        //Now we are connecting to the peer, set connection_peer to 0x00
        memset(&connection_peer, 0x00, 6);

        NRF_LOG_INFO("Peer address is a match");
        // Name is a match, initiate connection.
        err_code = sd_ble_gap_connect(&p_adv_report->peer_addr,
                                      &m_scan_params,
                                      &m_connection_param,
                                      APP_BLE_CONN_CFG_TAG);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Connection Request Failed, reason %d", err_code);
        }
    }
    else
    {
        //NRF_LOG_INFO("Advertisment wasn't match to %s ", p_adv_report->data.p_data);// m_target_periph_name);
        err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer);
        APP_ERROR_CHECK(err_code);
    }
}


/**@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;

    // For readability.
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;

    switch (p_ble_evt->header.evt_id)
    {
        // Upon connection, check which peripheral has connected, initiate DB
        // discovery, update LEDs status and resume scanning if necessary.
        case BLE_GAP_EVT_CONNECTED:
        {
            NRF_LOG_INFO("Connection 0x%x established, starting DB discovery.",
                         p_gap_evt->conn_handle);

            NRF_LOG_INFO("interval %d",  p_gap_evt->params.connected.conn_params.min_conn_interval);


            APP_ERROR_CHECK_BOOL(p_gap_evt->conn_handle < NRF_SDH_BLE_CENTRAL_LINK_COUNT);

            err_code = ble_nus_c_handles_assign(&m_nus_c[p_gap_evt->conn_handle],
                                                p_gap_evt->conn_handle,
                                                NULL);
            APP_ERROR_CHECK(err_code);

            err_code = ble_db_discovery_start(&m_db_disc[p_gap_evt->conn_handle],
                                              p_gap_evt->conn_handle);
            if (err_code != NRF_ERROR_BUSY)
            {
                APP_ERROR_CHECK(err_code);
            }

            scan_start();
            

        } break; // BLE_GAP_EVT_CONNECTED

        // Upon disconnection, reset the connection handle of the peer which disconnected, update
        // the LEDs status and start scanning again.
        case BLE_GAP_EVT_DISCONNECTED:
        {
            NRF_LOG_INFO("NUS central link 0x%x disconnected (reason: 0x%x)",
                         p_gap_evt->conn_handle,
                         p_gap_evt->params.disconnected.reason);



            scan_start();

        } break;

        case BLE_GAP_EVT_ADV_REPORT:
            on_adv_report(&p_gap_evt->params.adv_report);
            break;

        case BLE_GAP_EVT_TIMEOUT:
        {
            // We have not specified a timeout for scanning, so only connection attemps can timeout.
            if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
            {
                NRF_LOG_DEBUG("Connection request timed out.");
            }
            // Check if scaning times out and restart the scans
            if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN)
            {
                scan_start();
            }
        } break;

        case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
        {
            NRF_LOG_DEBUG("BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST.");
            // Accept parameters requested by peer.
            err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
                                        &p_gap_evt->params.conn_param_update_request.conn_params);
            APP_ERROR_CHECK(err_code);
        } break;

        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 initializing the NUS Client. */
static void nus_c_init(void)
{
    ret_code_t       err_code;
    ble_nus_c_init_t nus_c_init_obj;

    nus_c_init_obj.evt_handler = ble_nus_c_evt_handler;

    for (uint32_t i = 0; i < NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
    {
        err_code = ble_nus_c_init(&m_nus_c[i], &nus_c_init_obj);
        APP_ERROR_CHECK(err_code);
    }
}


/**@brief Function for initializing the BLE stack.
 *
 * @details Initializes the SoftDevice and the BLE event interrupts.
 */
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);
}

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
}

void saadc_init(void)
{
    ret_code_t err_code;
    nrf_saadc_channel_config_t channel_config6 
      = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6); //P0.30 = AN6 = Coil Current
    nrf_saadc_channel_config_t channel_config4 
      = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4); //P0.28 = AN4 = Batt 1 Temperature
    nrf_saadc_channel_config_t channel_config5 
      = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5); //P0.29 = AN5 = Batt 2 Temperature

    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &channel_config6);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(1, &channel_config4);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(2, &channel_config5);
    APP_ERROR_CHECK(err_code);

//    err_code = nrf_drv_saadc_buffer_convert(m_buffer, SAMPLES_IN_BUFFER);
//    APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling database discovery events.
 *
 * @details This function is 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 services.
 *
 * @param[in] p_event  Pointer to the database discovery event.
 */
static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
{
    NRF_LOG_DEBUG("call to ble_nus_on_db_disc_evt for instance %d and link 0x%x!",
                  p_evt->conn_handle,
                  p_evt->conn_handle);
    ble_nus_c_on_db_disc_evt(&m_nus_c[p_evt->conn_handle], p_evt);
}


/** @brief Database discovery 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 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 Handle any pending log operation(s), then sleep until the next event occurs.
 */
static void idle_state_handle(void)
{
    if (NRF_LOG_PROCESS() == false)
    {
        nrf_pwr_mgmt_run();
    }
}


/** @brief Function for initializing the 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();
}

void pwm_init(uint16_t freq)
{
    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            COIL_PWM, // channel 0
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = NRF_PWM_CLK_4MHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = freq,
        .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    // Init PWM without error handler
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
}

void pwm_update(uint16_t freq)
{
    nrf_drv_pwm_uninit(&m_pwm0);
    pwm_init(freq);
    pwm_update_duty_cycle(freq / 2);
}

void pwm_stop()
{
    nrf_drv_pwm_uninit(&m_pwm0);
}

// Set duty cycle between 0 and 100%
void pwm_update_duty_cycle(uint16_t duty_cycle)
{
    seq_values->channel_0 = duty_cycle;
    
    nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
}

static void fill_adv_array(uint8_t *array)
{
        array[0] = 0;//adc_conversion(power_ave,0,6);//GET_HI_CHAR(power_ave);
        array[1] = 0;//adc_conversion(batt_ave,6144,4);//GET_LO_CHAR(power_ave);
        array[2] = 0;//
        array[3] = 99;//
        array[4] = 0;//
        array[5] = 0;//
        array[6] = 0;//
        array[7] = 0;//module_bit;
        array[8] = 0x00;//spare
        array[9] = 0;//;
//        array[10] = 0;//;
//        array[11] = 0;//
//        array[12] = 0;//
//        array[13] = 0;//pressure_conversion();//;pressure_H;
//        array[14] = 0;//temperature_H;
//        array[15] = 88;//VERSION;
//        array[16] = 0x00;
}

/**@brief Function for putting the chip into sleep mode.
 *
 * @note This function will not return.
 */
static void sleep_mode_enter(void)
{
    uint32_t err_code;
    //uint32_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)
{
    uint32_t err_code;

    switch (ble_adv_evt)
    {
        case BLE_ADV_EVT_FAST:
            //err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
            //APP_ERROR_CHECK(err_code);
            break;
        case BLE_ADV_EVT_IDLE:
            sleep_mode_enter();
            break;
        default:
            break;
    }
}

/**@brief Function for initializing the Advertising functionality.
 */
static void advertising_init(void)
{
    uint32_t               err_code;
    ble_advertising_init_t init;

    memset(&init, 0, sizeof(init));

    uint8_t advData[1];
    //fill_adv_array(advData);

    ble_advdata_manuf_data_t manuf_specific_data;
    manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER;
    manuf_specific_data.data.p_data = advData;
    manuf_specific_data.data.size   = sizeof(advData);

    init.advdata.name_type          = BLE_ADVDATA_FULL_NAME;
    init.advdata.include_appearance = false;
    init.advdata.flags              = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
    init.advdata.p_manuf_specific_data = &manuf_specific_data;
    init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
    init.srdata.uuids_complete.p_uuids  = m_adv_uuids;
    init.config.ble_adv_fast_enabled  = true;
    init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
    init.config.ble_adv_fast_timeout  = APP_ADV_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);

    err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, m_advertising.adv_handle, 0);
    APP_ERROR_CHECK(err_code); 
}

/**@brief Function for starting advertising.
 */
static void advertising_start(void)
{
    uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
    APP_ERROR_CHECK(err_code);   
}

void advertising_idle(void)
{
    uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_IDLE);
    APP_ERROR_CHECK(err_code);   
}


/** @brief Function for initializing the timer.
 */
static void timer_init(void)
{
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

//    err_code = app_timer_start(adv_timer,65000,NULL);
    //NRF_LOG_INFO("error %d", err_code);
//    APP_ERROR_CHECK(err_code);
}

/**@brief Function for handling events from the GATT library. */
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
    if (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)
    {
        NRF_LOG_INFO("ATT MTU exchange completed.");

        m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
        NRF_LOG_INFO("Ble NUS max data length set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
    }
}


/**@brief Function for initializing the GATT module.
 */
static void gatt_init(void)
{
    ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
//    ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
    APP_ERROR_CHECK(err_code);
}

/** @brief Function initialization and configuration of RTC driver instance.
 */
static void rtc_config(void)
{
    uint32_t err_code;

    //Initialize RTC instance
    nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
    config.prescaler = 1023; //32 a second
    err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler);
    APP_ERROR_CHECK(err_code);

    //Enable tick event & interrupt
    nrf_drv_rtc_tick_enable(&rtc,true);

    //Set compare channel to trigger interrupt after COMPARE_COUNTERTIME seconds
    err_code = nrf_drv_rtc_cc_set(&rtc,2,COMPARE_COUNTERTIME * 32,true);
    APP_ERROR_CHECK(err_code);

    //Power on RTC instance
    nrf_drv_rtc_enable(&rtc);
}

void do_dfu(void)
{
    uint32_t err_code;

    //NRF_LOG_DEBUG("In ble_dfu_buttonless_bootloader_start_finalize\r\n");

    err_code = sd_power_gpregret_clr(0, 0xffffffff);
    VERIFY_SUCCESS(err_code);

    err_code = sd_power_gpregret_set(0, BOOTLOADER_DFU_START);
    VERIFY_SUCCESS(err_code);

    // Signal that DFU mode is to be enter to the power management module
    nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);

    //return NRF_SUCCESS;
}

int main(void)
{
    ble_gap_addr_t my_address;
    ret_code_t ret;

    current_state = STATE_START;

    log_init(); //TODO - remove this and test for side effects
    leds_button_init();

    memset(&connection_peer, 0x00, 6);
    
    //Test LEDs
    nrf_gpio_pin_set(LED_R);
    nrf_delay_ms(200);
    nrf_gpio_pin_clear(LED_R);
    nrf_gpio_pin_set(LED_G);
    nrf_delay_ms(200);
    nrf_gpio_pin_clear(LED_G);
    nrf_gpio_pin_set(LED_B);
    nrf_delay_ms(200);
    nrf_gpio_pin_clear(LED_B);

    bq25896_initial_code();
    lcd_initial_code();

    display_logo();
    nrf_gpio_pin_set(EN_PIN);
    nrf_delay_ms(2000);
    nrf_gpio_pin_clear(EN_PIN);

    timer_init();
    rtc_config();
    saadc_init();
    nrf_drv_saadc_calibrate_offset();
    pwm_update(PWM_VALUE);
    //pwm_update_duty_cycle(80);

    ret = nrf_drv_clock_init();
    APP_ERROR_CHECK(ret);

    //TODO - try removing next 3 lines
    NRF_LOG_INFO("USBD BLE UART example started.");
    ret = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(ret);

    // Initialize.

    ble_stack_init();
    gatt_init();
    gap_params_init();
    db_discovery_init();
    nus_c_init();
    ble_conn_state_init();
    advertising_init();
    advertising_start();

    //Get peer address of this device
    sd_ble_gap_addr_get(&my_address);

    //NOTE - Had to add this to stop PWM jitter
    sd_clock_hfclk_request();

    //blank off band records age = 0xFF
    for (uint8_t i=0;i<BAND_ARRAY_SIZE;i++)
    {
        //set the age to 0xFF = blank record
        band_array[i].age = 0xFF;
    }


//fix for multiple connections
    for (uint16_t i=0;i<NRF_SDH_BLE_CENTRAL_LINK_COUNT;i++)
    {
        m_db_disc[i].conn_handle=BLE_CONN_HANDLE_INVALID;
    }

    // Start execution.
    scan_start();

    for (;;)
    {
        idle_state_handle();
    }
}

Parents Reply Children
  • Thanks Joakim.

    The advertising init is totally different to that in the NUS example, doesn't seem to be consistent across the examples. I managed to update my code so it uses the adv init function from blinky.

    However I now can't get the power output function to work.

    How would I modify the blinky example below to change the adv transmit power output? The below doesn't work, gives a 3004 error.

    err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, &m_adv_handle, 8);
    APP_ERROR_CHECK(err_code);

    Thanks

    static void advertising_init(void)
    {
        ret_code_t    err_code;
        ble_advdata_t advdata;
        ble_advdata_t srdata;
    
        uint8_t testData[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
    
        ble_advdata_manuf_data_t manuf_specific_data;
        manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER;
        manuf_specific_data.data.p_data = testData;
        manuf_specific_data.data.size   = 0x08;
    
        ble_uuid_t adv_uuids[] = {{LBS_UUID_SERVICE, m_lbs.uuid_type}};
    
        // Build and set advertising data.
        memset(&advdata, 0, sizeof(advdata));
    
        advdata.name_type          = BLE_ADVDATA_FULL_NAME;
        advdata.include_appearance = true;
        advdata.flags              = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
        advdata.p_manuf_specific_data = &manuf_specific_data;
    
        memset(&srdata, 0, sizeof(srdata));
        srdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
        srdata.uuids_complete.p_uuids  = adv_uuids;
    
        err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
        APP_ERROR_CHECK(err_code);
    
        err_code = ble_advdata_encode(&srdata, m_adv_data.scan_rsp_data.p_data, &m_adv_data.scan_rsp_data.len);
        APP_ERROR_CHECK(err_code);
    
        ble_gap_adv_params_t adv_params;
    
        // Set advertising parameters.
        memset(&adv_params, 0, sizeof(adv_params));
    
        adv_params.primary_phy     = BLE_GAP_PHY_1MBPS;
        adv_params.duration        = APP_ADV_DURATION;
        adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
        adv_params.p_peer_addr     = NULL;
        adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY;
        adv_params.interval        = APP_ADV_INTERVAL;
    
        err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &adv_params);
        APP_ERROR_CHECK(err_code);
    }

  • Thanks for the info.

    Non connectable is not a massive deal for this application, would be nice to get it working but might give up on this for now as it is causing knock on issues else where.

Related