diff options
Diffstat (limited to 'MOST_UNICENS/hal_most_unicens.c')
-rw-r--r-- | MOST_UNICENS/hal_most_unicens.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/MOST_UNICENS/hal_most_unicens.c b/MOST_UNICENS/hal_most_unicens.c new file mode 100644 index 0000000..5e29b59 --- /dev/null +++ b/MOST_UNICENS/hal_most_unicens.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2017, Microchip Technology Inc. and its subsidiaries. + * Author Tobias Jahnke + * + * 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 +#include <string.h> +#include "hal-interface.h" +#include "audio-common.h" +#include "wrap-json.h" +#include "wrap_unicens.h" +#include "wrap_volume.h" + +#ifndef UCS2_CFG_PATH +# define UCS2_CFG_PATH "/home/agluser/DEVELOPMENT/AGL/BINDING/unicens2-binding/data" +#endif + +#define ALSA_CARD_NAME "Microchip MOST:1" +#define ALSA_DEVICE_ID "hw:1" +#define PCM_MAX_CHANNELS 6 + +static int master_volume; +static json_bool master_switch; +static int pcm_volume[PCM_MAX_CHANNELS]; + +static void unicens_request_card_values_cb(void *closure, int status, struct json_object *j_response) { + + json_object *j_obj; + int num_id; + int values[6]; + + AFB_INFO("unicens_request_card_values_cb: closure=%p status=%d, res=%s", closure, status, json_object_to_json_string(j_response)); + + json_object_object_get_ex(j_response, "response", &j_obj); + + if (json_object_is_type(j_obj, json_type_object)) { + + } + else if (json_object_is_type(j_obj, json_type_array)) { + AFB_ERROR("unicens_request_card_values_cb: array not handled yet"); + return; + } + else { + AFB_ERROR("unicens_request_card_values_cb: unknown response type"); + return; + } + + if (wrap_json_unpack(j_obj, "{s:i, s:[iiiiii!]}", "id", &num_id, "val", + &values[0], &values[1], &values[2], &values[3], &values[4], &values[5]) + == 0) { + AFB_NOTICE("unicens_request_card_values_cb: success, num id:%d", num_id); + } + else { + AFB_ERROR("unicens_request_card_values_cb: unpack failure"); + return; + } + +#if 0 + if (num_id == 2) { + wrap_volume_pcm(&values[0], 6); + } +#endif + +} + +__attribute__ ((unused)) static void unicens_request_card_values(const char* dev_id) { + + int err; + json_object *j_query = NULL; + + err = wrap_json_pack(&j_query, "{s:s, s:i}", "devid", dev_id, "mode", 0); + + if (err) { + AFB_ERROR("Failed to call wrap_json_pack"); + goto OnErrorExit; + } + + afb_service_call("alsacore", "ctlget", j_query, + &unicens_request_card_values_cb, + NULL); + + if (err) { + AFB_ERROR("Failed to call listconfig"); + goto OnErrorExit; + } + +OnErrorExit: + return; +} + +void unicens_master_vol_cb(halCtlsTagT tag, alsaHalCtlMapT *control, void* handle, json_object *j_obj) { + + const char *j_str = json_object_to_json_string(j_obj); + + if (wrap_json_unpack(j_obj, "[i!]", &master_volume) == 0) { + AFB_NOTICE("master_volume: %s, value=%d", j_str, master_volume); + wrap_volume_master(master_volume); + } + else { + AFB_NOTICE("master_volume: INVALID STRING %s", j_str); + } +} + +void unicens_master_switch_cb(halCtlsTagT tag, alsaHalCtlMapT *control, void* handle, json_object *j_obj) { + + const char *j_str = json_object_to_json_string(j_obj); + + if (wrap_json_unpack(j_obj, "[b!]", &master_switch) == 0) { + AFB_NOTICE("master_switch: %s, value=%d", j_str, master_switch); + } + else { + AFB_NOTICE("master_switch: INVALID STRING %s", j_str); + } +} + +void unicens_pcm_vol_cb(halCtlsTagT tag, alsaHalCtlMapT *control, void* handle, json_object *j_obj) { + + const char *j_str = json_object_to_json_string(j_obj); + + if (wrap_json_unpack(j_obj, "[iiiiii!]", &pcm_volume[0], &pcm_volume[1], &pcm_volume[2], &pcm_volume[3], + &pcm_volume[4], &pcm_volume[5]) == 0) { + AFB_NOTICE("pcm_vol: %s", j_str); + wrap_volume_pcm(pcm_volume, PCM_MAX_CHANNELS/*array size*/); + } + else { + AFB_NOTICE("pcm_vol: INVALID STRING %s", j_str); + } +} + +/* declare ALSA mixer controls */ +STATIC alsaHalMapT alsaHalMap[]= { + { .tag=Master_Playback_Volume, .cb={.callback=unicens_master_vol_cb, .handle=&master_volume}, .info="Sets master playback volume", + .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=1, .minval=0, .maxval=100, .step=1, .value=50, .name="Master Playback Volume"} + }, + /*{ .tag=Master_OnOff_Switch, .cb={.callback=unicens_master_switch_cb, .handle=&master_switch}, .info="Sets master playback switch", + .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_BOOLEAN, .count=1, .minval=0, .maxval=1, .step=1, .value=1, .name="Master Playback Switch"} + },*/ + { .tag=PCM_Playback_Volume, .cb={.callback=unicens_pcm_vol_cb, .handle=&pcm_volume}, .info="Sets PCM playback volume", + .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=6, .minval=0, .maxval=100, .step=1, .value=100, .name="PCM Playback Volume"} + }, + { .tag=EndHalCrlTag} /* marker for end of the array */ +} ; + +/* HAL sound card mapping info */ +STATIC alsaHalSndCardT alsaHalSndCard = { + .name = ALSA_CARD_NAME, /* WARNING: name MUST match with 'aplay -l' */ + .info = "HAL for MICROCHIP MOST sound card controlled by UNICENS binding", + .ctls = alsaHalMap, + .volumeCB = NULL, /* use default volume normalization function */ +}; + +/* initializes ALSA sound card, UNICENS API */ +STATIC int unicens_service_init() { + int err = 0; + char *config_file = NULL; + AFB_NOTICE("Initializing HAL-MOST-UNICENS-BINDING"); + + err = halServiceInit(afbBindingV2.api, &alsaHalSndCard); + if (err) { + AFB_ERROR("Cannot initialize ALSA soundcard."); + goto OnErrorExit; + } + + err= afb_daemon_require_api("UNICENS", 1); + if (err) { + AFB_ERROR("Failed to access UNICENS API"); + goto OnErrorExit; + } + + err = wrap_ucs_getconfig_sync(UCS2_CFG_PATH, &config_file); + if (err || (config_file == NULL)) { + AFB_ERROR("Failed to retrieve configuration"); + goto OnErrorExit; + } + else { + AFB_NOTICE("Found configuration: %s", config_file); + } + + err = wrap_ucs_subscribe_sync(); + if (err) { + AFB_ERROR("Failed to subscribe to UNICENS binding"); + goto OnErrorExit; + } + + err = wrap_ucs_initialize_sync(config_file); + free(config_file); + config_file = NULL; + + if (err) { + AFB_ERROR("Failed to initialize UNICENS binding"); + goto OnErrorExit; + } + + err = wrap_volume_init(); + if (err) { + AFB_ERROR("Failed to initialize wrapper for volume library"); + goto OnErrorExit; + } + + /* request of initial card values */ + /* unicens_request_card_values(ALSA_DEVICE_ID); */ + +OnErrorExit: + AFB_NOTICE("Initializing HAL-MOST-UNICENS-BINDING done.."); + return err; +} + +// This receive all event this binding subscribe to +PUBLIC void unicens_event_cb(const char *evtname, json_object *j_event) { + + if (strncmp(evtname, "alsacore/", 9) == 0) { + halServiceEvent(evtname, j_event); + return; + } + + if (strncmp(evtname, "UNICENS/", 8) == 0) { + //AFB_NOTICE("unicens_event_cb: evtname=%s, event=%s", evtname, json_object_get_string(j_event)); + if (strcmp(evtname, "UNICENS/node-availibility") == 0) { + + int node; + int available; + if (wrap_json_unpack(j_event, "{s:i,s:b}", "node", &node, "available", &available) == 0) { + AFB_NOTICE("Node-Availability: node=0x%03X, available=%d", node, available); + wrap_volume_node_avail(node, available); + } + } + + return; + } + + AFB_NOTICE("unicens_event_cb: UNHANDLED EVENT, evtname=%s, event=%s", evtname, json_object_get_string(j_event)); +} + +/* API prefix should be unique for each snd card */ +PUBLIC const struct afb_binding_v2 afbBindingV2 = { + .api = "hal-most-unicens", + .init = unicens_service_init, + .verbs = halServiceApi, + .onevent = unicens_event_cb, +}; |