Bluetooth: testlib: `bt_testlib_connect`: better error logs

Changes to logging:
 - Don't log "Connected" if there was an error.
 - Identify the relevant bt_conn object in log messages by its index.
 - Special case non-fatal errors:
  - Failure due to out of free conn object is INF.
 - Improve transparancy of error messages:
  - For errno, include the name of the API.
  - For HCI errors, include the common prefix of the symbols
    'BT_HCI_ERR_' so they are easier to look up.

This change includes some light refactoring to make the code more
understandable, but does not change any behavior.

Signed-off-by: Aleksander Wasaznik <aleksander.wasaznik@nordicsemi.no>
diff --git a/tests/bluetooth/common/testlib/src/connect.c b/tests/bluetooth/common/testlib/src/connect.c
index e8f5a90..9e181a5 100644
--- a/tests/bluetooth/common/testlib/src/connect.c
+++ b/tests/bluetooth/common/testlib/src/connect.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2023 Nordic Semiconductor ASA
+/* Copyright (c) 2023-2024 Nordic Semiconductor ASA
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -12,10 +12,10 @@
 LOG_MODULE_REGISTER(bt_testlib_connect, LOG_LEVEL_INF);
 
 struct bt_testlib_connect_closure {
-	uint8_t conn_err;
-	struct bt_conn **conn;
+	uint8_t conn_cb_connected_err;
+	struct bt_conn **connp;
 	struct k_mutex lock;
-	struct k_condvar done;
+	struct k_condvar conn_cb_connected_match;
 };
 
 /* Context pool (with capacity of one). */
@@ -23,63 +23,89 @@
 static K_MUTEX_DEFINE(g_ctx_lock);
 static struct bt_testlib_connect_closure *g_ctx;
 
-static void connected_cb(struct bt_conn *conn, uint8_t conn_err)
+static void on_conn_cb_connected(struct bt_conn *conn, uint8_t conn_err)
 {
 	/* Loop over each (allocated) item in pool. */
 
 	k_mutex_lock(&g_ctx_lock, K_FOREVER);
 
-	if (g_ctx && conn == *g_ctx->conn) {
-		g_ctx->conn_err = conn_err;
-		k_condvar_signal(&g_ctx->done);
+	if (g_ctx && conn == *g_ctx->connp) {
+		g_ctx->conn_cb_connected_err = conn_err;
+		k_condvar_signal(&g_ctx->conn_cb_connected_match);
 	}
 
 	k_mutex_unlock(&g_ctx_lock);
 }
 
-BT_CONN_CB_DEFINE(conn_callbacks) = {
-	.connected = connected_cb,
+BT_CONN_CB_DEFINE(conn_cb) = {
+	.connected = on_conn_cb_connected,
 };
 
-int bt_testlib_connect(const bt_addr_le_t *peer, struct bt_conn **conn)
+int bt_testlib_connect(const bt_addr_le_t *peer, struct bt_conn **connp)
 {
-	int api_err;
+	int err;
 	struct bt_testlib_connect_closure ctx = {
-		.conn = conn,
+		.connp = connp,
 	};
+	uint8_t conn_index;
 
-	__ASSERT_NO_MSG(conn);
-	__ASSERT_NO_MSG(*conn == NULL);
+	__ASSERT_NO_MSG(connp);
+	__ASSERT_NO_MSG(*connp == NULL);
 
-	k_condvar_init(&ctx.done);
+	k_condvar_init(&ctx.conn_cb_connected_match);
 
+	/* If multiple threads call into this funciton, they will wait
+	 * for their turn here. The Zephyr host does not support
+	 * concurrent connection creation.
+	 */
 	k_sem_take(&g_ctx_free, K_FOREVER);
 	k_mutex_lock(&g_ctx_lock, K_FOREVER);
 	g_ctx = &ctx;
 
-	api_err = bt_conn_le_create(peer, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, conn);
+	err = bt_conn_le_create(peer, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, connp);
 
-	if (!api_err) {
-		LOG_INF("Connecting.. conn %u", bt_conn_index(*conn));
-		k_condvar_wait(&ctx.done, &g_ctx_lock, K_FOREVER);
-		LOG_INF("Connect complete");
+	if (!err) {
+		conn_index = bt_conn_index(*connp);
+		LOG_INF("bt_conn_le_create ok conn %u", conn_index);
+
+		k_condvar_wait(&ctx.conn_cb_connected_match, &g_ctx_lock, K_FOREVER);
 	}
 
 	g_ctx = NULL;
 	k_mutex_unlock(&g_ctx_lock);
 	k_sem_give(&g_ctx_free);
 
-	if (api_err) {
-		LOG_ERR("bt_conn_le_create err %d", api_err);
-		__ASSERT_NO_MSG(api_err < 0);
-		return api_err;
+	/* Merge the error codes. The errors from `bt_conn_le_create`
+	 * are negative, leaving the positive space for the HCI errors
+	 * from `conn_cb_connected`.
+	 */
+	__ASSERT_NO_MSG(err <= 0);
+	__ASSERT_NO_MSG(0 <= ctx.conn_cb_connected_err);
+	__ASSERT_NO_MSG(!err || !ctx.conn_cb_connected_err);
+	err = err + ctx.conn_cb_connected_err;
+
+	/* This is just logging. */
+	switch (err) {
+	case -ENOMEM:
+		LOG_INF("bt_conn_le_create -ENOMEM: No free connection objects available.");
+		break;
+	case 0:
+		LOG_INF("conn %u: connected", conn_index);
+		break;
+	case BT_HCI_ERR_UNKNOWN_CONN_ID:
+		LOG_INF("conn %u: timed out", conn_index);
+		break;
+	default:
+		if (err < 0) {
+			LOG_ERR("bt_conn_le_create err %d", err);
+		} else {
+			LOG_ERR("conn %u: BT_HCI_ERR_ 0x%02x", conn_index, err);
+		}
 	}
 
-	if (ctx.conn_err) {
-		LOG_ERR("Connect HCI err %d", ctx.conn_err);
-		__ASSERT_NO_MSG(ctx.conn_err >= 0);
-		return ctx.conn_err;
-	}
+	/* Note: `connp` is never unrefed in this funciton, even in case
+	 * of errors. This is as documented.
+	 */
 
-	return 0;
+	return err;
 }