/* * Copyright 2019 Microchip Technology Inc. and its subsidiaries * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #ifndef AFB_BINDING_VERSION # define AFB_BINDING_VERSION 3 #endif #include #include #include #include #include "wrap-unicens.h" #include "microphone.h" #define HB(value) ((uint8_t)((uint16_t)(value) >> 8)) #define LB(value) ((uint8_t)((uint16_t)(value) & (uint16_t)0xFFU)) /***************************************************************************** * types */ enum microphone_mode { MICROPHONE_MODE_NONE = 0, MICROPHONE_MODE_DOA = 1, MICROPHONE_MODE_THINKING = 2, MICROPHONE_MODE_SPEAKING = 3, MICROPHONE_MODE_ERROR = 4, MICROPHONE_MODE_WAKING = 5, MICROPHONE_MODE_ENDING = 6, MICROPHONE_MODE_STATIC = 7, MICROPHONE_MODE_CYLON = 8, MICROPHONE_MODE_RAINBOW = 9, MICROPHONE_MODE_WHEEL = 10, MICROPHONE_MODE_UNKNOWN = 11 }; /***************************************************************************** * local prototypes */ 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 */ #define NODE_ID ((uint16_t)0x520U) #define MSG_ID_MODE 0x1001U /* set LED mode */ #define MSG_ID_LED_DIR 0x1002U /* set LED direction*/ #define MSG_ID_DOA 0x1003U /* get audio direction */ #define MSG_ID_LED_COL 0x1006U /* set static LED color */ #define MSG_OP_SET 0x00U #define MSG_OP_GET 0x01U #define MSG_MAX_PAYLOAD_SZ 10U 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 */ extern void microphone_availablility_changed(uint16_t node_id, bool available) { if (node_id == NODE_ID) { AFB_API_DEBUG(afbBindingRoot, "%s: microphone 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; } } static int microphone_mode_set(enum microphone_mode mode) { AFB_API_NOTICE(afbBindingRoot, "microphone_mode_set value=%d", mode); if (_available == false) { AFB_API_NOTICE(afbBindingRoot, "%s: node is not available", __func__); return -1; } if (mode < MICROPHONE_MODE_UNKNOWN) { _tx_payload[0] = MSG_OP_SET; _tx_payload[1] = (uint8_t)mode; wrap_ucs_sendmessage_sync(NODE_ID, MSG_ID_MODE, _tx_payload, 2U); } else { AFB_API_NOTICE(afbBindingRoot, "%s: given mode is unknown", __func__); return -1; } 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; } } } static int microphone_led_direction_set(uint16_t direction) { AFB_API_NOTICE(afbBindingRoot, "microphone_led_direction_set executed"); if (_available == false) { AFB_API_NOTICE(afbBindingRoot, "%s: node is not available", __func__); return -1; } _tx_payload[0] = MSG_OP_SET; _tx_payload[1] = HB(direction); _tx_payload[2] = LB(direction); wrap_ucs_sendmessage_sync(NODE_ID, MSG_ID_LED_DIR, _tx_payload, 3U); return 0; } static int microphone_static_ledcolor_set(uint8_t red, uint8_t green, uint8_t blue) { AFB_API_NOTICE(afbBindingRoot, "microphone_static_led_color_set executed"); if (_available == false) { AFB_API_NOTICE(afbBindingRoot, "%s: node is not available", __func__); return -1; } _tx_payload[0] = MSG_OP_SET; _tx_payload[1] = red; _tx_payload[2] = green; _tx_payload[3] = blue; wrap_ucs_sendmessage_sync(NODE_ID, MSG_ID_LED_COL, _tx_payload, 4U); return 0; } /***************************************************************************** * JSON API */ extern void microphone_mode_set_api(afb_req_t request) { char *str_mode = NULL; struct json_object* j_obj = afb_req_json(request); AFB_API_NOTICE(afbBindingRoot, "UNICENS-CONTROLLER: %s:%s", __func__, json_object_get_string(j_obj)); if (wrap_json_unpack(j_obj, "{s:s}", "value", &str_mode) == 0) { AFB_API_NOTICE(afbBindingRoot, "UNICENS-CONTROLLER: decoded value=%s", str_mode); enum microphone_mode mic_mode = MICROPHONE_MODE_UNKNOWN; if (strcmp(str_mode, "none") == 0) { mic_mode = MICROPHONE_MODE_NONE; } else if (strcmp(str_mode, "doa") == 0) { mic_mode = MICROPHONE_MODE_DOA; } else if (strcmp(str_mode, "thinking") == 0) { mic_mode = MICROPHONE_MODE_THINKING; } else if (strcmp(str_mode, "speaking") == 0) { mic_mode = MICROPHONE_MODE_SPEAKING; } else if (strcmp(str_mode, "error") == 0) { mic_mode = MICROPHONE_MODE_ERROR; } else if (strcmp(str_mode, "waking") == 0) { mic_mode = MICROPHONE_MODE_WAKING; } else if (strcmp(str_mode, "ending") == 0) { mic_mode = MICROPHONE_MODE_ENDING; } else if (strcmp(str_mode, "static") == 0) { mic_mode = MICROPHONE_MODE_STATIC; } else if (strcmp(str_mode, "cylon") == 0) { mic_mode = MICROPHONE_MODE_CYLON; } else if (strcmp(str_mode, "rainbow") == 0) { mic_mode = MICROPHONE_MODE_RAINBOW; } else if (strcmp(str_mode, "wheel") == 0) { mic_mode = MICROPHONE_MODE_WHEEL; } if (mic_mode < MICROPHONE_MODE_UNKNOWN) { microphone_mode_set(mic_mode); afb_req_success(request, NULL, NULL); } else { afb_req_fail(request, "argument 'value' is not set to a known value", NULL); } } else { afb_req_fail(request, "missing argument 'value'", NULL); } } 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); } } extern void microphone_led_dir_set_api(afb_req_t request) { int direction = 0; struct json_object* j_obj = afb_req_json(request); AFB_API_NOTICE(afbBindingRoot, "UNICENS-CONTROLLER: %s:%s", __func__, json_object_get_string(j_obj)); if (wrap_json_unpack(j_obj, "{s:i}", "value", &direction) == 0) { AFB_API_NOTICE(afbBindingRoot, "UNICENS-CONTROLLER: decoded value=%d", direction); if ((direction >= 0) && (direction < 360)) { if (microphone_led_direction_set((uint16_t)direction) == 0) { afb_req_success(request, NULL, NULL); } else { afb_req_fail(request, "Call failed. Microphone not available?", NULL); } } else { afb_req_fail(request, "Argument 'value' not in range 0...359.", NULL); } } else { afb_req_fail(request, "Missing argument 'value'", NULL); } } extern void microphone_static_ledcolor_set_api(afb_req_t request) { int red, green, blue = 0; struct json_object* j_obj = afb_req_json(request); AFB_API_NOTICE(afbBindingRoot, "UNICENS-CONTROLLER: %s:%s", __func__, json_object_get_string(j_obj)); if (wrap_json_unpack(j_obj, "{s:i, s:i, s:i}", "red", &red, "green", &green, "blue", &blue) == 0) { AFB_API_NOTICE(afbBindingRoot, "UNICENS-CONTROLLER: decoded rgb=%d,%d,%d", red, green, blue); if ( (red >= 0) && (red <= 0xFF) && (green >= 0) && (green <= 0xFF) && (blue >= 0) && (blue <= 0xFF)) { if (microphone_static_ledcolor_set((uint8_t)red, (uint8_t)green, (uint8_t)blue) == 0) { afb_req_success(request, NULL, NULL); } else { afb_req_fail(request, "Call failed. Microphone not available?", NULL); } } else { afb_req_fail(request, "Argument 'value' not in range 0..255.", NULL); } } else { afb_req_fail(request, "Error while parsing arguments.", NULL); } } extern void microphone_is_available_api(afb_req_t request) { struct json_object* j_obj = afb_req_json(request); struct json_object* j_resp = json_object_new_object(); AFB_API_NOTICE(afbBindingRoot, "UNICENS-CONTROLLER: %s:%s", __func__, json_object_get_string(j_obj)); if (j_resp != NULL) { wrap_json_pack(&j_resp, "{s:b}", "available", (int)_available); afb_req_reply(request, j_resp, NULL, "response successful"); } else { afb_req_fail(request, "Cannot allocate response object.", NULL); } }