From e91eaa18befd14446d280311c9bd5c05f29801f0 Mon Sep 17 00:00:00 2001 From: Tobias Jahnke Date: Tue, 15 Oct 2019 15:14:30 +0200 Subject: unicens-controller: add DOA feature Introduce a new API to retrieve the current direction of audio (DOA) recognized by the microphone. Bug-AGL: SPEC-2899 Signed-off-by: Tobias Jahnke Change-Id: I387efaeaf0cffd06b3d88efbeeaf2ef7eb23c780 --- binding/binding.c | 7 ++++ binding/microphone/microphone.c | 71 ++++++++++++++++++++++++++++++++++++- binding/microphone/microphone.h | 2 ++ binding/wrap-unicens/wrap-unicens.c | 50 ++++++++++++++++++++++++++ binding/wrap-unicens/wrap-unicens.h | 3 ++ 5 files changed, 132 insertions(+), 1 deletion(-) (limited to 'binding') diff --git a/binding/binding.c b/binding/binding.c index cebc54a..1d19fdb 100644 --- a/binding/binding.c +++ b/binding/binding.c @@ -38,6 +38,7 @@ static int init(afb_api_t api) { AFB_API_NOTICE(afbBindingRoot, "UNICENS-CONTROLLER: INIT"); wrap_ucs_init(api); wrap_ucs_subscribe_sync(); + wrap_ucs_subscriberx_sync(); return 0; } @@ -47,10 +48,15 @@ static void on_availability_cb(uint16_t node, bool available) { microphone_availablility_changed(node, available); } +static void on_message_rx_cb(uint16_t node, uint16_t msg_id, uint16_t data_sz, uint8_t *data_ptr) { + microphone_message_received(node, msg_id, data_sz, data_ptr); +} + /* callback for handling events */ static void onevent(afb_api_t api, const char *event, struct json_object *object) { AFB_API_NOTICE(afbBindingRoot, "UNICENS-CONTROLLER: Event: %s object: %s", event, json_object_get_string(object)); wrap_ucs_interpret_event(event, object, &on_availability_cb); + wrap_ucs_interpretrx_event(event, object, &on_message_rx_cb); } static void ping(afb_req_t request) { @@ -63,6 +69,7 @@ static const afb_verb_t verbs[] = { {.verb = "slimamp_master_volume_set", .session = AFB_SESSION_NONE, .callback = slimamp_master_vol_set_api, .auth = NULL}, {.verb = "amplifier_master_volume_set", .session = AFB_SESSION_NONE, .callback = amplifier_master_vol_set_api, .auth = NULL}, {.verb = "microphone_mode_set", .session = AFB_SESSION_NONE, .callback = microphone_mode_set_api, .auth = NULL}, + {.verb = "microphone_doa_get", .session = AFB_SESSION_NONE, .callback = microphone_doa_get_api, .auth = NULL}, {NULL} }; diff --git a/binding/microphone/microphone.c b/binding/microphone/microphone.c index dc43cd3..344fbd7 100644 --- a/binding/microphone/microphone.c +++ b/binding/microphone/microphone.c @@ -49,6 +49,8 @@ enum microphone_mode */ static int microphone_mode_set(enum microphone_mode mode); +static int microphone_doa_get(void); +static void microphone_doa_status(uint16_t data_sz, uint8_t *data_ptr); /***************************************************************************** * local variables and definitions @@ -56,11 +58,15 @@ static int microphone_mode_set(enum microphone_mode mode); #define NODE_ID ((uint16_t)0x520U) #define MSG_ID_MODE 0x1001U +#define MSG_ID_DOA 0x1003U #define MSG_OP_SET 0x00U +#define MSG_OP_GET 0x01U #define MSG_MAX_PAYLOAD_SZ 2U static uint8_t _tx_payload[MSG_MAX_PAYLOAD_SZ]; static bool _available = false; +static bool _doa_running = false; +static afb_req_t _req_doa_get = NULL; /***************************************************************************** * functions @@ -70,6 +76,23 @@ extern void microphone_availablility_changed(uint16_t node_id, bool available) { if (node_id == NODE_ID) { AFB_API_DEBUG(afbBindingRoot, "%s: amplifier new availability=%d", __func__, available); _available = available; + _doa_running = false; + } +} + +extern void microphone_message_received(uint16_t node, uint16_t msg_id, uint16_t data_sz, uint8_t *data_ptr) { + + if (node != NODE_ID) { + return; + } + + switch (msg_id) { + case MSG_ID_DOA: + microphone_doa_status(data_sz, data_ptr); + break; + default: + AFB_API_NOTICE(afbBindingRoot, "microphone_message_received node=%d, msg_id=%d, data_sz=%d", node, msg_id, data_sz); + break; } } @@ -93,6 +116,40 @@ static int microphone_mode_set(enum microphone_mode mode) { return 0; } +static int microphone_doa_get(void) { + AFB_API_NOTICE(afbBindingRoot, "microphone_doa_get started"); + if (_available == false) { + AFB_API_NOTICE(afbBindingRoot, "%s: node is not available", __func__); + return -1; + } + + if (_doa_running) { + AFB_API_NOTICE(afbBindingRoot, "%s: request is still running", __func__); + return -2; + } + + _tx_payload[0] = MSG_OP_GET; + wrap_ucs_sendmessage_sync(NODE_ID, MSG_ID_DOA, _tx_payload, 1U); + + return 0; +} + +static void microphone_doa_status(uint16_t data_sz, uint8_t *data_ptr) { + uint16_t angle = 0U; + + if ((data_sz == 3U) && (data_ptr[0] == 0x0CU)) { + angle = (uint16_t)((uint16_t)data_ptr[1] << 8 | (uint16_t)data_ptr[2]); + AFB_API_NOTICE(afbBindingRoot, "microphone_doa_status: angle=%d", angle); + if (_req_doa_get != NULL) { + struct json_object* j_resp; + j_resp = json_object_new_object(); + wrap_json_pack(&j_resp, "{s:i}", "value", angle); + afb_req_reply(_req_doa_get, j_resp, NULL, "response successful"); + afb_req_unref(_req_doa_get); + _req_doa_get = NULL; + } + } +} /***************************************************************************** * JSON API @@ -150,4 +207,16 @@ extern void microphone_mode_set_api(afb_req_t request) { else { afb_req_fail(request, "missing argument 'value'", NULL); } -} \ No newline at end of file +} + +extern void microphone_doa_get_api(afb_req_t request) { + struct json_object* j_obj = afb_req_json(request); + + if (microphone_doa_get() != 0) { + AFB_API_NOTICE(afbBindingRoot, "function call failed: %s:%s", __func__, json_object_get_string(j_obj)); + afb_req_fail(request, "function call failed", NULL); + } + else { + _req_doa_get = afb_req_addref(request); + } +} diff --git a/binding/microphone/microphone.h b/binding/microphone/microphone.h index 01fbcb2..27ee4ea 100644 --- a/binding/microphone/microphone.h +++ b/binding/microphone/microphone.h @@ -22,5 +22,7 @@ /* notification */ extern void microphone_availablility_changed(uint16_t node_id, bool available); +extern void microphone_message_received(uint16_t node, uint16_t msg_id, uint16_t data_sz, uint8_t *data_ptr); /* JSON API */ extern void microphone_mode_set_api(afb_req_t request); +extern void microphone_doa_get_api(afb_req_t request); diff --git a/binding/wrap-unicens/wrap-unicens.c b/binding/wrap-unicens/wrap-unicens.c index e5d4570..84b94cd 100644 --- a/binding/wrap-unicens/wrap-unicens.c +++ b/binding/wrap-unicens/wrap-unicens.c @@ -66,6 +66,56 @@ extern int wrap_ucs_subscribe_sync(void) { return 0; } +/* + * Subscribes to unicens2-binding RX message events. + * \return Returns 0 if successful, otherwise != 0". + */ +extern int wrap_ucs_subscriberx_sync(void) { + int err; + + json_object *j_response, *j_query = NULL; + char *error, *info; + + /* Build an empty JSON object */ + if((err = wrap_json_pack(&j_query, "{}"))) { + AFB_API_ERROR(api_handle_, "Failed to create subscribe RX json object"); + return err; + } + + if((err = afb_api_call_sync(api_handle_, "UNICENS", "subscriberx", j_query, &j_response, &error, &info))) { + AFB_API_ERROR(api_handle_, "Fail subscribing to UNICENS RX events"); + return err; + } + else { + AFB_API_NOTICE(api_handle_, "Subscribed to UNICENS RX events, res=%s", json_object_to_json_string(j_response)); + json_object_put(j_response); + } + + return 0; +} + +extern int wrap_ucs_interpretrx_event(const char *event, struct json_object *object, wrap_ucs_rx_message_cb_t callback) { + int node_id = 0; + int msg_id = 0; + uint8_t *data_ptr = NULL; + size_t data_sz = 0; + + if (strcmp(event, "UNICENS/rx-message") != 0) { + return -1; // unhandled event + } + + if (wrap_json_unpack(object, "{s:i, s:i, s?Y}", "node", &node_id, "msgid", &msg_id, "data", &data_ptr, &data_sz) != 0) { + AFB_API_NOTICE(api_handle_, "Parsing rx-message failed."); + return -2; + } + + if (callback != NULL) { + callback((uint16_t)node_id, (uint16_t)msg_id, (uint16_t)data_sz, data_ptr); + } + + return 0; +} + extern int wrap_ucs_interpret_event(const char *event, struct json_object *object, wrap_ucs_availability_cb_t callback) { int node_id = 0; int available = false; diff --git a/binding/wrap-unicens/wrap-unicens.h b/binding/wrap-unicens/wrap-unicens.h index a6e2f43..781f6cc 100644 --- a/binding/wrap-unicens/wrap-unicens.h +++ b/binding/wrap-unicens/wrap-unicens.h @@ -28,6 +28,7 @@ extern int wrap_ucs_init(afb_api_t apiHandle); /* Asynchronous API: result callback */ typedef void (*wrap_ucs_availability_cb_t)(uint16_t node, bool available); +typedef void (*wrap_ucs_rx_message_cb_t)(uint16_t node, uint16_t msg_id, uint16_t data_sz, uint8_t *data_ptr); typedef void (*wrap_ucs_result_cb_t)(uint8_t result, void *user_ptr); /* Asynchronous API: functions */ @@ -39,6 +40,8 @@ extern int wrap_ucs_i2cwrite(uint16_t node, /* Synchronous API: functions */ extern int wrap_ucs_subscribe_sync(void); +extern int wrap_ucs_subscriberx_sync(void); extern int wrap_ucs_interpret_event(const char *event, struct json_object *object, wrap_ucs_availability_cb_t callback); +extern int wrap_ucs_interpretrx_event(const char *event, struct json_object *object, wrap_ucs_rx_message_cb_t callback); extern int wrap_ucs_i2cwrite_sync(uint16_t node, uint8_t *data_ptr, uint8_t data_sz); extern int wrap_ucs_sendmessage_sync(uint16_t src_addr, uint16_t msg_id, uint8_t *data_ptr, uint8_t data_sz); -- cgit 1.2.3-korg