/* * Copyright (C) 2018 "IoT.bzh" * Author Jonathan Aillet * * 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 #include #include #include #include #include #include "4a-hal-utilities-hal-api-handler.h" #include "4a-hal-utilities-hal-streams-handler.h" #include "4a-hal-utilities-ping.h" #include "4a-internals-hal-api-loader.h" #include "4a-internals-hal-alsacore-link.h" #include "4a-internals-hal-cb.h" #include "4a-internals-hal-mixer-link.h" /******************************************************************************* * Json parsing functions using controller * ******************************************************************************/ // Config Section definition static CtlSectionT ctrlSectionsDefault[] = { { .key = "haldependencies", .loadCB = InternalHalHalDependenciesConfig }, { .key = "resources", .loadCB = PluginConfig }, { .key = "halmixer", .loadCB = InternalHalHalMixerConfig }, { .key = "onload", .loadCB = OnloadConfig }, { .key = "controls", .loadCB = ControlConfig }, { .key = "events", .loadCB = EventConfig }, { .key = "halmap", .loadCB = InternalHalHalMapConfig }, { .key = NULL } }; /******************************************************************************* * Dynamic HAL verbs' functions * ******************************************************************************/ // Every HAL export the same API & Interface Mapping from SndCard to AudioLogic is done through alsaHalSndCardT static afb_verb_t InternalHalApiStaticVerbs[] = { /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ { .verb = "ping", .callback = HalUtlPing, .info = "Ping for test"}, { .verb = "info", .callback = InternalHalInfoVerb, .info = "List available dependencies/streams/controls for this api" }, { .verb = "subscribe", .callback = InternalHalSubscribe, .info = "Subscribe to event(s) for values changes (streams/controls) for this api" }, { .verb = "unsubscribe", .callback = InternalHalUnsubscribe, .info = "Unsubscribe to event(s) for values changes (streams/controls) for this api" }, { .verb = HAL_ALL_STREAMS_VERB, .callback = HalUtlActionOnAllStream, .info = "Send a stream action on all streams" }, { .verb = NULL } // Marker for end of the array }; /******************************************************************************* * Dynamic API functions for internals hal * ******************************************************************************/ static int InternalHalInitOneApi(afb_api_t apiHandle) { int err; CtlConfigT *ctrlConfig; struct HalData *currentHalData; if(! apiHandle) return -1; // Retrieve section config from api handle ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) return -2; currentHalData = (struct HalData *) getExternalData(ctrlConfig); if(! currentHalData) return -3; // Fill HalDatadata structure currentHalData->internal = 1; currentHalData->uid = (char *) ctrlConfig->uid; currentHalData->info = (char *) ctrlConfig->info; currentHalData->author = (char *) ctrlConfig->author; currentHalData->version = (char *) ctrlConfig->version; currentHalData->date = (char *) ctrlConfig->date; currentHalData->internalHalData->apiHandle = apiHandle; currentHalData->internalHalData->ctrlConfig = ctrlConfig; currentHalData->internalHalData->streamUpdates = afb_api_make_event(apiHandle, HAL_STREAM_UPDATES_EVENT_NAME); if(! currentHalData->internalHalData->streamUpdates) return -4; // TBD JAI: handle refresh of hal status for dynamic card (/dev/by-id) err = CtlConfigExec(apiHandle, ctrlConfig); if(err < 0) { AFB_API_ERROR(apiHandle, "Error %i caught when trying to apply current internal hal controller sections", err); currentHalData->status = HAL_STATUS_INIT_FAILED; } if(err > 0) AFB_API_WARNING(apiHandle, "Warning %i raised when trying to apply current internal hal controller sections", err); return 0; } static int InternalHalLoadOneApi(void *cbdata, afb_api_t apiHandle) { int err; CtlConfigT *ctrlConfig; CtlSectionT *ctrlCurrentSections; if(! cbdata || ! apiHandle) return -1; ctrlConfig = (CtlConfigT*) cbdata; // Save closure as api's data context afb_api_set_userdata(apiHandle, ctrlConfig); // Add static internal hal verbs if(afb_api_set_verbs_v3(apiHandle, InternalHalApiStaticVerbs)) { AFB_API_ERROR(apiHandle, "Load Section : fail to register static V2 verbs"); return -2; } ctrlCurrentSections = malloc(sizeof(ctrlSectionsDefault)); if(! ctrlCurrentSections) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate current internal hal section data structure for controller"); return -3; } memcpy(ctrlCurrentSections, ctrlSectionsDefault, sizeof(ctrlSectionsDefault)); // Load section for corresponding Api err = CtlLoadSections(apiHandle, ctrlConfig, ctrlCurrentSections); if(err < 0) { AFB_API_ERROR(apiHandle, "Error %i caught when trying to load current internal hal controller sections", err); return -4; } if(err > 0) AFB_API_WARNING(apiHandle, "Warning %i raised when trying to load current internal hal controller sections", err); // Declare an event manager for this Api afb_api_on_event(apiHandle, InternalHalDispatchApiEvent); // Init Api function (does not receive user closure ???) afb_api_on_init(apiHandle, InternalHalInitOneApi); return 0; } int InternalHalCreateApi(afb_api_t apiHandle, char *path, struct HalMgrData *halMgrData) { int err; CtlConfigT *ctrlConfig; if(! apiHandle || ! path || ! halMgrData) return -1; // Create one Api per file ctrlConfig = CtlLoadMetaData(apiHandle, path); if(! ctrlConfig) { AFB_API_ERROR(apiHandle, "No valid internal hal config file in : '%s'", path); return -2; } if(! ctrlConfig->api) { AFB_API_ERROR(apiHandle, "API Missing from metadata in : '%s'", path); return -3; } err = HalUtlAddHalDataAndCreateHalApi(apiHandle, halMgrData, ctrlConfig, InternalHalLoadOneApi); if(err) { AFB_API_ERROR(apiHandle, "Error %i happened while trying to add hal api data and create new api", err); return -4; } return 0; } int InternalHalDeleteApi(afb_api_t apiHandle, struct cds_list_head *halDataListHead, struct HalData *toDeleteHalData) { int err; char *toDeleteApiName; if(! apiHandle || ! toDeleteHalData) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } err = InternalHalUnmanageAllHalMap(toDeleteHalData->internalHalData->apiHandle, &toDeleteHalData->internalHalData->halMapListHead, &toDeleteHalData->internalHalData->probedDevicesListHead); if(err) { AFB_API_ERROR(apiHandle, "Error %i happened while trying to unmanage all halmap of '%s' hal api", err, toDeleteHalData->apiName); return -2; } toDeleteApiName = strdup(toDeleteHalData->apiName); if(! toDeleteApiName) { AFB_API_ERROR(apiHandle, "Didn't succeed to store (allocate) 'apiName' string"); return -3; } err = HalUtlRemoveHalDataAndDeleteHalApi(toDeleteHalData->internalHalData->apiHandle, toDeleteHalData, halDataListHead); if(err) { AFB_API_ERROR(apiHandle, "Error %i happened while trying to delete '%s' api and to remove all its data", err, toDeleteApiName); free(toDeleteApiName); return -4; } AFB_API_NOTICE(apiHandle, "Api '%s' and all its data has been deleted", toDeleteApiName); free(toDeleteApiName); return 0; } int InternalHalCreateAllApi(afb_api_t apiHandle, struct HalMgrData *halMgrData) { int index; char *dirList, *fileName, *fullPath; char filePath[CONTROL_MAXPATH_LEN]; filePath[CONTROL_MAXPATH_LEN - 1] = '\0'; json_object *configJ, *entryJ; if(! apiHandle || ! halMgrData) return -1; AFB_API_NOTICE(apiHandle, "Begining to create all APIs"); dirList = getenv("CONTROL_CONFIG_PATH"); if(! dirList) dirList = CONTROL_CONFIG_PATH; configJ = CtlConfigScan(dirList, "hal"); if(! configJ) { AFB_API_WARNING(apiHandle, "No hal-(binder-middle-name)*.json config file(s) found in %s, 4a-hal-manager will only works with external hal", dirList); return 0; } // We load 1st file others are just warnings for(index = 0; index < (int) json_object_array_length(configJ); index++) { entryJ = json_object_array_get_idx(configJ, index); if(wrap_json_unpack(entryJ, "{s:s, s:s !}", "fullpath", &fullPath, "filename", &fileName)) { AFB_API_ERROR(apiHandle, "HOOPs invalid JSON entry = %s", json_object_get_string(entryJ)); return -2; } strncpy(filePath, fullPath, sizeof(filePath) - 1); strncat(filePath, "/", sizeof(filePath) - 1); strncat(filePath, fileName, sizeof(filePath) - 1); if(InternalHalCreateApi(apiHandle, filePath, halMgrData) < 0) return -3; } return 0; } int InternalHalDeleteAllApi(afb_api_t apiHandle, struct HalMgrData *halMgrData) { int err; char *toDeleteApiName; struct HalData *currentHalData; if(! apiHandle || ! halMgrData) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } cds_list_for_each_entry(currentHalData, &halMgrData->halDataListHead, node) { if(! currentHalData->apiName) return -2; toDeleteApiName = strdup(currentHalData->apiName); if(! toDeleteApiName) { AFB_API_ERROR(apiHandle, "Didn't succeed to store (allocate) 'apiName' string"); return -3; } err = InternalHalDeleteApi(apiHandle, &halMgrData->halDataListHead, currentHalData); if(err) { AFB_API_ERROR(apiHandle, "Error %i happened when tried to delete %s api", err, toDeleteApiName); free(toDeleteApiName); return -4; } free(toDeleteApiName); } return 0; }