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

NRF_ERROR_INVALID_STATE error on new characteristic

I am trying to modify the existing Thingy-52 code to have a 'new' characteristic.  I used the existing Thingy code to 'clone' a new characteristic (a 2nd microphone channel).  My problem is that whenever I try to write to the channel I get an NRF_ERROR_INVALID_STATE error from sd_ble_gatts_hvx() that is used to send the data.  In researching NRF_ERROR_INVALID_STATE it appears there can be 3 causes of this failure, 1 - invalid connection state, 2 - Notifications/indications not enabled, 3 - MTU exchange ongoing.  I am thinking that somehow notifications are not enabled.  Is this done from the 'app'/client side of things?  Where are notifications enabled.
Just to answer setup questions... here is my code: 
Added a new BLE characteristic to Thingy Sound service for right stereo sound channel
Step #1)  Add UUID of new characteristic to list (ble_tss.h)
#define BLE_UUID_TSS_CONFIG_CHAR      0x0501   /**< The UUID of the config char */
#define BLE_UUID_TSS_SPKR_CHAR        0x0502   /**< The UUID of the speaker char */
#define BLE_UUID_TSS_SPKR_STAT_CHAR   0x0503   /**< The UUID of the speaker char */
#define BLE_UUID_TSS_MIC_CHAR         0x0504   /**< The UUID of the microphone char */
#ifdef STEREO
#define BLE_UUID_TSS_RIGHT_MIC_CHAR   0x0505   /**< The UUID of the right mic char */
#endif
Step #2) Changed sound service structure to include right mic handle (ble_tss.h)
struct ble_tss_s
{
    uint8_t                  uuid_type;         /**< UUID type for Thingy Sound Service Base UUID. */
    uint16_t                 service_handle;    /**< Handle of Thingy Sound Service (as provided by the S110 SoftDevice). */
    ble_gatts_char_handles_t spkr_handles;      /**< Handles related to the speaker characteristic (from S132 SoftDevice). */
    ble_gatts_char_handles_t mic_handles;       /**< Handles related to the microphone characteristic (from S132 SoftDevice). */
    ble_gatts_char_handles_t right_mic_handles; /**< Handles related to the right microphone characteristic (from S132 SoftDevice). */
    ble_gatts_char_handles_t spkr_stat_handles; /**< Handles related to the speaker status characteristic (from S132 SoftDevice). */
    ble_gatts_char_handles_t config_handles;    /**< Handles related to the config characteristic (from S132 SoftDevice). */
    uint16_t                 conn_handle;       /**< Handle of the current connection (as provided by the S110 SoftDevice). */
                                                /**< BLE_CONN_HANDLE_INVALID if not in a connection. */
    bool                     is_mic_notif_enabled; /**< Variable to indicate if the peer has enabled notification of the char*/
    bool                     is_spkr_stat_notif_enabled; /**< Variable to indicate if the peer has enabled notification of char.*/
    ble_tss_evt_handler_t    evt_handler;                /**< Event handler to be called for handling received data. */
};
typedef struct ble_tss_s ble_tss_t;
 
Step #3) Initialize sound service for new characteristic.
thingy_init() → m_sound_init(): sets ble event handler, sound service init routine, data handlers (step 4)
 uint32_t m_sound_init(m_ble_service_handle_t * p_handle)
{
    uint32_t           err_code;
    drv_speaker_init_t speaker_init;
     NULL_PARAM_CHECK(p_handle);
     NRF_LOG_INFO("Sound_init \r\n");
     p_handle->ble_evt_cb = sound_on_ble_evt;
     p_handle->init_cb    = sound_service_init;
     return drv_mic_init(drv_mic_data_handler, drv_right_mic_data_handler);
}
 
Step 4) Set data handlers, initialize audio streams.
static drv_mic_data_handler_t m_left_data_handler;
static drv_mic_data_handler_t m_right_data_handler;
uint32_t drv_mic_init(drv_mic_data_handler_t left_data_handler, drv_mic_data_handler_t right_data_handler)
{
    uint32_t err_code;
    m_audio_enabled = false;
    m_left_data_handler   = left_data_handler;
    m_right_data_handler  = right_data_handler;
    for(uint32_t i = 0; i < PDM_BUF_NUM; i++)
    {
        m_pdm_buf[i].free = true;
    }
     mic_power_off();
     return drv_audio_init(m_audio_buffer_handler);
}
 
// Initialize BLE Thingy Sound service
 
thingy_init() → m_ble_init() → services_init() → ble_tss_init()
 uint32_t ble_tss_init(ble_tss_t * p_tss, const ble_tss_init_t * p_tss_init)
{
    uint32_t      err_code;
    ble_uuid_t    ble_uuid;
    ble_uuid128_t tss_base_uuid = TSS_BASE_UUID;
    VERIFY_PARAM_NOT_NULL(p_tss);
    VERIFY_PARAM_NOT_NULL(p_tss_init);
    // Initialize the service structure.
    p_tss->conn_handle                  = BLE_CONN_HANDLE_INVALID;
    p_tss->evt_handler                  = p_tss_init->evt_handler;
    p_tss->is_mic_notif_enabled         = false;
    p_tss->is_spkr_stat_notif_enabled   = false;
     // Add a custom base UUID.
    err_code = sd_ble_uuid_vs_add(&tss_base_uuid, &p_tss->uuid_type);
    VERIFY_SUCCESS(err_code);
     ble_uuid.type = p_tss->uuid_type;
    ble_uuid.uuid = BLE_UUID_TSS_SERVICE;
     // Add the service.
    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                        &ble_uuid,
                                        &p_tss->service_handle);
    VERIFY_SUCCESS(err_code);
     // Add the config Characteristic.
    err_code = config_char_add(p_tss, p_tss_init);
    VERIFY_SUCCESS(err_code);
     // Add the speaker Characteristic.
    err_code = spkr_char_add(p_tss, p_tss_init);
    VERIFY_SUCCESS(err_code);
     // Add the speaker Characteristic.
    err_code = spkr_stat_char_add(p_tss, p_tss_init);
    VERIFY_SUCCESS(err_code);
     // Add the microphone Characteristic.
    err_code = mic_char_add(p_tss, p_tss_init);
    VERIFY_SUCCESS(err_code);
 
    // Add the right channel microphone Characteristic.
    err_code = right_mic_char_add(p_tss, p_tss_init);
    VERIFY_SUCCESS(err_code);
 
    return NRF_SUCCESS;
}
Step 5: Data handler- drv_right_mic_data_handler.  When data comes in from PDM it eventually triggers a packet of information to be sent by drv_right_mic_data_handler().  This sequence works correctly up to the point that the data is sent.  Ble_tss_right_mic_set() error with value of 8 – NRF_ERROR_INVALID_STATE
static uint32_t drv_right_mic_data_handler(m_audio_frame_t * p_frame)
{
    uint32_t err_code;
     if (p_frame->data_size != CONFIG_AUDIO_FRAME_SIZE_BYTES)
    {
        NRF_LOG_WARNING("drv_right_mic_data_handler: size = %d \r\n", p_frame->data_size);
    }
    err_code = ble_tss_right_mic_set(&m_tss, p_frame->data, p_frame->data_size);
    if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("drv_right_mic_data_handler: Failed to send\r\n");
        }
    }
    return NRF_SUCCESS;
}
uint32_t ble_tss_right_mic_set(ble_tss_t * p_tss, uint8_t * p_data, uint16_t size)
{
    ble_gatts_hvx_params_t hvx_params;
 
    VERIFY_PARAM_NOT_NULL(p_tss);
 
    if ((p_tss->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_tss->is_mic_notif_enabled))
    {
        return NRF_ERROR_INVALID_STATE;
    }
 
    if (size > BLE_TSS_MIC_FRAME_SIZE)
    {
        return NRF_ERROR_INVALID_PARAM;
    }
 
    memset(&hvx_params, 0, sizeof(hvx_params));
 
    hvx_params.handle = p_tss->right_mic_handles.value_handle;
    hvx_params.p_data = p_data;
    hvx_params.p_len  = &size;
    hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
 
    return sd_ble_gatts_hvx(p_tss->conn_handle, &hvx_params);
}
Parents
  • It is common that sd_ble_gatts_hvx() return NRF_ERROR_INVALID_STATE upon power on and initial connection, e.g. because the peer need to connect, do a database discovery of the peripheral and then enable the notifications in the database. I think the question for you is whether sd_ble_gatts_hvx() always return NRF_ERROR_INVALID_STATE (even for instance after other notifications are working)?

  • The new characteristic always errors.  In my testing I establish a connection between the Thingy app and my modified code.  I then have it start to transmit the sound data for both the existing 'right' channel and my new 'left' sound channel.  The right channel transmits fine with no errors.  The new 'left' channel continuously errors.  For the new characteristic I tried to 'clone' the set up and handler code from the existing one as much as possible

    Does the Thingy app somehow 'enable' the notifications on a per characteristic basis?  That would explain why I get an error.

  • SentinelLighting said:
    Does the Thingy app somehow 'enable' the notifications on a per characteristic basis?  That would explain why I get an error.

    Could be, do you have the possibility to use nRF Connect app to manually enable the notifications?

    Kenneth

Reply Children
Related