uint32_t ble_gatts_attr_context_t_dec(uint8_t const * const p_buf,
                                      uint32_t              buf_len,
                                      uint32_t * const      p_index,
                                      void * const          p_void_attr_context)
{
    uint32_t                   error_code = NRF_SUCCESS;
    ble_gatts_attr_context_t * p_context  = (ble_gatts_attr_context_t *) p_void_attr_context;

    error_code = ble_uuid_t_dec(p_buf, buf_len, p_index, &(p_context->srvc_uuid));
    SER_ASSERT(error_code == NRF_SUCCESS, error_code);
    error_code = ble_uuid_t_dec(p_buf, buf_len, p_index, &(p_context->char_uuid));
    SER_ASSERT(error_code == NRF_SUCCESS, error_code);
    error_code = ble_uuid_t_dec(p_buf, buf_len, p_index, &(p_context->desc_uuid));
    SER_ASSERT(error_code == NRF_SUCCESS, error_code);

    SER_ASSERT_LENGTH_LEQ(5, buf_len - *p_index);
    uint16_dec(p_buf, buf_len, p_index, &(p_context->srvc_handle));
    uint16_dec(p_buf, buf_len, p_index, &(p_context->value_handle));
    uint8_dec(p_buf, buf_len, p_index, &(p_context->type));
    return error_code;
}
uint32_t ble_gattc_service_t_dec(uint8_t const * const p_buf,
                                 uint32_t              buf_len,
                                 uint32_t * const      p_index,
                                 void * const          p_void_struct)
{
    uint32_t              error_code = NRF_SUCCESS;
    ble_gattc_service_t * p_service  = (ble_gattc_service_t *) p_void_struct;

    error_code = ble_uuid_t_dec(p_buf, buf_len, p_index, &(p_service->uuid));
    SER_ASSERT(error_code == NRF_SUCCESS, error_code);
    error_code = ble_gattc_handle_range_t_dec(p_buf, buf_len, p_index, &(p_service->handle_range));
    SER_ASSERT(error_code == NRF_SUCCESS, error_code);

    return error_code;
}
uint32_t ble_gatts_evt_read_t_dec(uint8_t const * const p_buf,
                                  uint32_t              buf_len,
                                  uint32_t * const      p_index,
                                  uint32_t * const      p_struct_len,
                                  void * const          p_void_read)
{
    SER_ASSERT_NOT_NULL(p_buf);
    SER_ASSERT_NOT_NULL(p_index);

    uint32_t err_code      = NRF_SUCCESS;
    uint32_t in_struct_len = *p_struct_len;

    *p_struct_len = sizeof (ble_gatts_evt_read_t);

    uint16_t handle;
    err_code = uint16_t_dec(p_buf, buf_len, p_index, &handle);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    ble_uuid_t uuid;
    err_code = ble_uuid_t_dec(p_buf, buf_len, p_index, &uuid);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    uint16_t offset;
    err_code = uint16_t_dec(p_buf, buf_len, p_index, &offset);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    if (p_void_read != NULL)
    {
        ble_gatts_evt_read_t * p_read = (ble_gatts_evt_read_t *)p_void_read;

        SER_ASSERT_LENGTH_LEQ(*p_struct_len, in_struct_len);

        p_read->handle = handle;
        p_read->uuid   = uuid;
        p_read->offset = offset;
    }

    return err_code;
}
uint32_t ble_gatts_evt_write_t_dec(uint8_t const * const p_buf,
                                   uint32_t              buf_len,
                                   uint32_t * const      p_index,
                                   uint32_t * const      p_struct_len,
                                   void * const          p_void_write)
{
    SER_ASSERT_NOT_NULL(p_buf);
    SER_ASSERT_NOT_NULL(p_index);
    SER_ASSERT_NOT_NULL(p_struct_len);

    uint32_t err_code      = NRF_SUCCESS;
    uint32_t in_struct_len = *p_struct_len;

    *p_struct_len = offsetof(ble_gatts_evt_write_t, data);

    uint16_t handle;
    err_code = uint16_t_dec(p_buf, buf_len, p_index, &handle);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    ble_uuid_t uuid;
    err_code = ble_uuid_t_dec(p_buf, buf_len, p_index, &uuid);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    uint8_t op;
    err_code = uint8_t_dec(p_buf, buf_len, p_index, &op);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    uint8_t auth_required;
    err_code = uint8_t_dec(p_buf, buf_len, p_index, &auth_required);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    uint16_t offset;
    err_code = uint16_t_dec(p_buf, buf_len, p_index, &offset);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    uint16_t len;
    err_code = uint16_t_dec(p_buf, buf_len, p_index, &len);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    *p_struct_len += len;

    if (p_void_write != NULL)
    {
        ble_gatts_evt_write_t * p_write = (ble_gatts_evt_write_t *)p_void_write;

        SER_ASSERT_LENGTH_LEQ(*p_struct_len, in_struct_len);

        p_write->handle = handle;
        p_write->uuid   = uuid;
        p_write->op     = op;
        p_write->auth_required = auth_required;
        p_write->offset = offset;
        p_write->len    = len;

        SER_ASSERT_LENGTH_LEQ(p_write->len, buf_len - *p_index);
        memcpy(p_write->data, &p_buf[*p_index], p_write->len);
    }

    *p_index += len;

    return err_code;
}