aboutsummaryrefslogtreecommitdiffstats
path: root/src/4a-internals-hal/4a-internals-hal-value-handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/4a-internals-hal/4a-internals-hal-value-handler.c')
-rw-r--r--src/4a-internals-hal/4a-internals-hal-value-handler.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/src/4a-internals-hal/4a-internals-hal-value-handler.c b/src/4a-internals-hal/4a-internals-hal-value-handler.c
new file mode 100644
index 0000000..64083a9
--- /dev/null
+++ b/src/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