diff options
Diffstat (limited to '4a-hal/4a-internals-hal/4a-internals-hal-value-handler.c')
-rw-r--r-- | 4a-hal/4a-internals-hal/4a-internals-hal-value-handler.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-value-handler.c b/4a-hal/4a-internals-hal/4a-internals-hal-value-handler.c new file mode 100644 index 0000000..64083a9 --- /dev/null +++ b/4a-hal/4a-internals-hal/4a-internals-hal-value-handler.c @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet <jonathan.aillet@iot.bzh> + * + * 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 <stdio.h> +#include <string.h> + +#include <limits.h> +#include <math.h> + +#include <wrap-json.h> + +#include <afb/afb-binding.h> + +#include "4a-internals-hal-value-handler.h" +#include "4a-internals-hal-alsacore-link.h" + +/******************************************************************************* + * Simple conversion value to/from percentage functions * + ******************************************************************************/ + +int InternalHalConvertValueToPercentage(double val, double min, double max) +{ + double range; + + range = max - min; + if(range <= 0) + return -INT_MAX; + + val -= min; + + return (int) round(val / range * 100); +} + +int InternalHalConvertPercentageToValue(int percentage, int min, int max) +{ + int range; + + range = max - min; + if(range <= 0) + return -INT_MAX; + + return (int) round((double) percentage * (double) range * 0.01 + (double) min); +} + +/******************************************************************************* + * Convert json object from percentage to value * + ******************************************************************************/ + +int InternalHalConvertJsonValueForIntegerControl(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *toConvertJ, + json_object **ConvertedJ, + enum ConversionType requestedConversion) +{ + int initialValue, convertedValue; + + if(! json_object_is_type(toConvertJ, json_type_int)) { + AFB_API_ERROR(apiHandle, + "Can't convert json value, unrecognized json format (must be an integer) : '%s'", + json_object_get_string(toConvertJ)); + return -1; + } + + initialValue = json_object_get_int(toConvertJ); + + switch(requestedConversion) { + case CONVERSION_NORMALIZED_TO_ALSACORE: + if(initialValue < 0 || initialValue > 100) { + AFB_API_ERROR(apiHandle, + "Cannot convert '%i' value, value should be between 0 and 100 ('%s')", + initialValue, + json_object_get_string(toConvertJ)); + return -2; + } + + convertedValue = InternalHalConvertPercentageToValue(initialValue, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + if(convertedValue == -INT_MAX) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to convert %i (using min %i et max %i)", + initialValue, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + return -3; + } + + if(alsaCtlProperties->step) { + // Round value to the nearest step + convertedValue = (int) round((double) convertedValue / (double) alsaCtlProperties->step); + convertedValue *= alsaCtlProperties->step; + } + break; + + case CONVERSION_ALSACORE_TO_NORMALIZED: + convertedValue = InternalHalConvertValueToPercentage(initialValue, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + if(convertedValue == -INT_MAX) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to convert %i (using min %i et max %i)", + initialValue, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + return -4; + } + + break; + + default: + AFB_API_ERROR(apiHandle, + "Can't convert '%i' value, unrecognized conversion type : '%i'", + initialValue, + (int) requestedConversion); + *ConvertedJ = NULL; + return -5; + } + + *ConvertedJ = json_object_new_int(convertedValue); + + return 0; +} + +int InternalHalConvertJsonValueForBooleanControl(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *toConvertJ, + json_object **ConvertedJ, + enum ConversionType requestedConversion) +{ + int initialValue; + + switch(json_object_get_type(toConvertJ)) { + case json_type_int: + initialValue = json_object_get_int(toConvertJ); + break; + + case json_type_boolean: + initialValue = json_object_get_boolean(toConvertJ); + break; + + default: + AFB_API_ERROR(apiHandle, + "Can't convert json value, unrecognized format (must be an integer or a boolean) : '%s'", + json_object_get_string(toConvertJ)); + return -1; + } + + if(initialValue < 0 || initialValue > 1) { + AFB_API_ERROR(apiHandle, + "Cannot convert '%i' value, value should be 0 or 1 ('%s')", + initialValue, + json_object_get_string(toConvertJ)); + return -2; + } + + switch(requestedConversion) { + case CONVERSION_NORMALIZED_TO_ALSACORE: + *ConvertedJ = json_object_new_int(initialValue); + break; + + case CONVERSION_ALSACORE_TO_NORMALIZED: + *ConvertedJ = json_object_new_boolean(initialValue); + break; + + default: + AFB_API_ERROR(apiHandle, + "Can't convert '%i' value, unrecognized conversion type : '%i'", + initialValue, + (int) requestedConversion); + *ConvertedJ = NULL; + return -3; + } + + return 0; +} + +int InternalHalConvertJsonValues(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *toConvertJ, + json_object **ConvertedJ, + enum ConversionType requestedConversion) +{ + int conversionError = 0, idx, count; + + json_type toConvertType; + json_object *toConvertObjectJ, *convertedValueJ, *convertedArrayJ; + + *ConvertedJ = NULL; + + toConvertType = json_object_get_type(toConvertJ); + count = (toConvertType == json_type_array) ? (int) json_object_array_length(toConvertJ) : 1; + + convertedArrayJ = json_object_new_array(); + + for(idx = 0; idx < count; idx++) { + if(toConvertType == json_type_array) + toConvertObjectJ = json_object_array_get_idx(toConvertJ, idx); + else + toConvertObjectJ = toConvertJ; + + switch(alsaCtlProperties->type) { + case SND_CTL_ELEM_TYPE_INTEGER: + case SND_CTL_ELEM_TYPE_INTEGER64: + conversionError = InternalHalConvertJsonValueForIntegerControl(apiHandle, + alsaCtlProperties, + toConvertObjectJ, + &convertedValueJ, + requestedConversion); + if(conversionError) { + AFB_API_ERROR(apiHandle, + "Error %i happened in when trying to convert index %i for integer control ('%s')", + conversionError, + idx, + json_object_get_string(toConvertObjectJ)); + json_object_put(convertedArrayJ); + return -(idx + 1); + } + break; + + case SND_CTL_ELEM_TYPE_BOOLEAN: + conversionError = InternalHalConvertJsonValueForBooleanControl(apiHandle, + alsaCtlProperties, + toConvertObjectJ, + &convertedValueJ, + requestedConversion); + if(conversionError) { + AFB_API_ERROR(apiHandle, + "Error %i happened in when trying to convert index %i for boolean control ('%s')", + conversionError, + idx, + json_object_get_string(toConvertObjectJ)); + json_object_put(convertedArrayJ); + return -(idx + 1); + } + break; + + default: + AFB_API_ERROR(apiHandle, + "Conversion not handle for the alsa control type %i", + (int) alsaCtlProperties->type); + json_object_put(convertedArrayJ); + return -(idx + 1); + } + + json_object_array_put_idx(convertedArrayJ, idx, convertedValueJ); + } + + *ConvertedJ = convertedArrayJ; + + return 0; +} + +int InternalHalChangePreviousValuesUsingJson(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *requestedPercentageVariationJ, + json_object *previousControlValuesJ, + json_object **ChangedJ) +{ + int requestedPercentageVariation, requestedVariation, toChangeValue, changedValue, idx, count; + + char *requestedPercentageVariationString, *conversionEnd; + + json_object *toChangeObjectJ, *changedArrayJ; + + *ChangedJ = NULL; + + requestedPercentageVariationString = (char *) json_object_get_string(requestedPercentageVariationJ); + + requestedPercentageVariation = (int) strtol(requestedPercentageVariationString, &conversionEnd, 10); + if(conversionEnd == requestedPercentageVariationString) { + AFB_API_ERROR(apiHandle, + "Tried to increase/decrease an integer control \ + but string sent in json is not a increase/decrease string : '%s'", + json_object_get_string(requestedPercentageVariationJ)); + return -1; + } + + if(alsaCtlProperties->type != SND_CTL_ELEM_TYPE_INTEGER && + alsaCtlProperties->type != SND_CTL_ELEM_TYPE_INTEGER64) { + AFB_API_ERROR(apiHandle, + "Tried to increase/decrease values on a incompatible \ + control type (%i), control type must be an integer", + alsaCtlProperties->type); + return -2; + } + + if(requestedPercentageVariation < -100 || requestedPercentageVariation > 100) { + AFB_API_ERROR(apiHandle, + "Tried to increase/decrease values but specified change is \ + not a valid percentage, it should be between -100 and 100"); + return -3; + } + + requestedVariation = InternalHalConvertPercentageToValue((int) abs(requestedPercentageVariation), + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + if(requestedVariation == -INT_MAX) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to convert %i (using min %i et max %i)", + requestedPercentageVariation, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + return -4; + } + + if(requestedPercentageVariation < 0) + requestedVariation = -requestedVariation; + + count = (int) json_object_array_length(previousControlValuesJ); + + changedArrayJ = json_object_new_array(); + + for(idx = 0; idx < count; idx++) { + toChangeObjectJ = json_object_array_get_idx(previousControlValuesJ, idx); + + if(! json_object_is_type(toChangeObjectJ, json_type_int)) { + AFB_API_ERROR(apiHandle, + "Current json object %s is not an integer", + json_object_get_string(toChangeObjectJ)); + return -(10 + idx); + } + + toChangeValue = json_object_get_int(toChangeObjectJ); + + if((toChangeValue + requestedVariation) < alsaCtlProperties->minval) + changedValue = alsaCtlProperties->minval; + else if((toChangeValue + requestedVariation) > alsaCtlProperties->maxval) + changedValue = alsaCtlProperties->maxval; + else + changedValue = toChangeValue + requestedVariation; + + json_object_array_put_idx(changedArrayJ, idx, json_object_new_int(changedValue)); + } + + *ChangedJ = changedArrayJ; + + return 0; +}
\ No newline at end of file |