diff --git a/test/unittest/platform/common/adc_test.c b/test/unittest/platform/common/adc_test.c index e3bb663d..aeb48461 100644 --- a/test/unittest/platform/common/adc_test.c +++ b/test/unittest/platform/common/adc_test.c @@ -75,12 +75,8 @@ struct AdcTester *AdcTesterGet(void) { int32_t ret; static struct AdcTester tester; - static bool hasInit = false; HDF_LOGE("%s: enter", __func__); - if (hasInit) { - return &tester; - } ret = AdcTestGetConfig(&tester.config); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: read config failed:%d", __func__, ret); @@ -91,11 +87,20 @@ struct AdcTester *AdcTesterGet(void) HDF_LOGE("%s: open adc device:%u failed", __func__, tester.config.devNum); return NULL; } - hasInit = true; HDF_LOGI("%s: done", __func__); return &tester; } +static void AdcTesterPut(struct AdcTester *tester) +{ + if (tester == NULL) { + HDF_LOGE("%s: tester is NULL", __func__); + return; + } + AdcClose(tester->handle); + tester->handle = NULL; +} + int32_t AdcTestRead(void) { struct AdcTester *tester = NULL; @@ -113,11 +118,13 @@ int32_t AdcTestRead(void) value[i] = 0; ret = AdcRead(tester->handle, tester->config.channel, &value[i]); if (ret != HDF_SUCCESS || value[i] >= (1U << tester->config.dataWidth)) { + AdcTesterPut(tester); HDF_LOGE("%s: read value failed, ret:%d", __func__, ret); return HDF_ERR_IO; } } + AdcTesterPut(tester); HDF_LOGI("%s: done", __func__); return HDF_SUCCESS; } @@ -142,11 +149,13 @@ static int AdcTestThreadFunc(void *param) if (ret != HDF_SUCCESS) { HDF_LOGE("%s: AdcRead failed, ret:%d", __func__, ret); *((int32_t *)param) = 1; + AdcTesterPut(tester); return HDF_ERR_IO; } } *((int32_t *)param) = 1; + AdcTesterPut(tester); HDF_LOGI("%s: done", __func__); return val; } @@ -217,6 +226,7 @@ int32_t AdcTestReliability(void) (void)AdcRead(tester->handle, tester->config.maxChannel + 1, &val); // invalid val pointer (void)AdcRead(tester->handle, tester->config.channel, NULL); + AdcTesterPut(tester); HDF_LOGI("%s: done", __func__); return HDF_SUCCESS; } @@ -247,7 +257,10 @@ static int32_t AdcIfPerformanceTest(void) useTime = endMs - startMs; HDF_LOGI("----->interface performance test:[start:%lld(ms) - end:%lld(ms) = %lld (ms)] < 1ms[%d]\r\n", startMs, endMs, useTime, useTime < 1 ? true : false); + AdcTesterPut(tester); + return HDF_SUCCESS; } + AdcTesterPut(tester); return HDF_FAILURE; } diff --git a/test/unittest/platform/virtual/adc_linux_virtual_iio_driver.c b/test/unittest/platform/virtual/adc_linux_virtual_iio_driver.c new file mode 100644 index 00000000..771071e7 --- /dev/null +++ b/test/unittest/platform/virtual/adc_linux_virtual_iio_driver.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "hdf_log.h" +#include "hdf_base.h" + +#define ADC_SCALE 32680000 +#define ADC_SCALE_DATA 100000 +#define ADC_VIRTUAL_RAW_DATA 119 +#define REAL_BITS 16 +#define STORAGE_BITS 16 +#define SHIFT_BITS 0 +#define SCAN_MASKS 0xF +#define BUS_NUM 2 + +enum AdcScanIndex { + ADC_SCAN_VOLTAGE_1, + ADC_SCAN_VOLTAGE_2, +}; + +struct VirtualAdcDev { + char *name; + int BusNum; + struct mutex lock; +}; + +static int AdcReadChannelData(struct iio_dev *indioDev, struct iio_chan_spec const *chan, int *val) +{ + if (val == NULL) { + HDF_LOGE("%s: val is NULL", __func__); + return -EINVAL; + } + (void)indioDev; + (void)chan; + *val = ADC_VIRTUAL_RAW_DATA; + return IIO_VAL_INT; +} + +/* + * val : The value written by the application, val is the integer part if it is a fractional value. + * val2 : The value written by the application, if it is a fractional value, val2 is the fractional part. +*/ +static int AdcReadRaw(struct iio_dev *indioDev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) +{ + struct VirtualAdcDev *dev = NULL; + int ret; + + if (indioDev == NULL || chan == NULL || val == NULL || val2 == NULL) { + HDF_LOGE("%s: Illegal parameter", __func__); + return -EINVAL; + } + if (ADC_SCALE_DATA == 0) { + HDF_LOGE("%s: ADC_SCALE_DATA is Illegal", __func__); + return -EINVAL; + } + + dev = iio_priv(indioDev); + switch (mask) { + case IIO_CHAN_INFO_RAW: + iio_device_claim_direct_mode(indioDev); + mutex_lock(&dev->lock); + ret = AdcReadChannelData(indioDev, chan, val); + mutex_unlock(&dev->lock); + iio_device_release_direct_mode(indioDev); + break; + case IIO_CHAN_INFO_SCALE: + *val = ADC_SCALE / ADC_SCALE_DATA; + *val2 = ADC_SCALE % ADC_SCALE_DATA; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + HDF_LOGE("%s: mask is Illegal", __func__); + ret = -EINVAL; + break; + } + + return ret; +} + +static const struct iio_chan_spec AdcChannels[] = { + { + .type = IIO_VOLTAGE, + .differential = 1, + .indexed = 1, + .channel = ADC_SCAN_VOLTAGE_1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = ADC_SCAN_VOLTAGE_1, + .scan_type = { + .sign = 's', + .realbits = REAL_BITS, + .storagebits = STORAGE_BITS, + .shift = SHIFT_BITS, + .endianness = IIO_BE, + }, + }, + { + .type = IIO_VOLTAGE, + .differential = 1, + .indexed = 1, + .channel = ADC_SCAN_VOLTAGE_2, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = ADC_SCAN_VOLTAGE_2, + .scan_type = { + .sign = 's', + .realbits = REAL_BITS, + .storagebits = STORAGE_BITS, + .shift = SHIFT_BITS, + .endianness = IIO_BE, + }, + }, +}; + +static const struct iio_info AdcIioInfo = { + .read_raw = AdcReadRaw, +}; + +static void VirtualAdcDevRelease(struct device *dev) +{ + (void)dev; +} + +static struct platform_device g_virtualAdcPlatformDevice = { + .name = "virtual_adc_dev", + .id = -1, + .dev = { + .release = VirtualAdcDevRelease, + } +}; + +static int VirtualAdcPlatformProbe(struct platform_device *pdev) +{ + struct VirtualAdcDev *adcInfo = NULL; + struct iio_dev *indioDev = NULL; + int ret; + + indioDev = devm_iio_device_alloc(&pdev->dev, sizeof(*adcInfo)); + if (!indioDev) { + HDF_LOGE("%s: malloc iio_dev fail", __func__); + return -ENOMEM; + } + adcInfo = iio_priv(indioDev); + adcInfo->name = "virtual-adc-3516"; + adcInfo->BusNum = BUS_NUM; + + indioDev->name = KBUILD_MODNAME; + indioDev->channels = AdcChannels; + indioDev->num_channels = ARRAY_SIZE(AdcChannels); + indioDev->available_scan_masks = SCAN_MASKS; + indioDev->info = &AdcIioInfo; + indioDev->modes = INDIO_DIRECT_MODE; + + platform_set_drvdata(pdev, indioDev); + + ret = iio_device_register(indioDev); + if (ret < 0) { + HDF_LOGE("%s: iio device register fail", __func__); + return ret; + } + + return HDF_SUCCESS; +} + +static int VirtualAdcPlatformRemove(struct platform_device *pdev) +{ + struct iio_dev *indioDev = NULL; + + indioDev = platform_get_drvdata(pdev); + if (indioDev == NULL) { + HDF_LOGE("%s: iio device is NULL", __func__); + return -EINVAL; + } + iio_device_unregister(indioDev); + platform_set_drvdata(pdev, NULL); + + return HDF_SUCCESS; +} + +static struct platform_driver g_virtualAdcPlatformDriver = { + .driver = { + .name = "virtual_adc_dev", + .owner = THIS_MODULE, + }, + .probe = VirtualAdcPlatformProbe, + .remove = VirtualAdcPlatformRemove, +}; + +static int __init VirtualAdcInit(void) +{ + int ret; + + ret = platform_device_register(&g_virtualAdcPlatformDevice); + if (ret == 0) { + ret = platform_driver_register(&g_virtualAdcPlatformDriver); + } + + return ret; +} + +static void __exit VirtualAdcExit(void) +{ + platform_device_unregister(&g_virtualAdcPlatformDevice); + platform_driver_unregister(&g_virtualAdcPlatformDriver); +} +module_init(VirtualAdcInit); +module_exit(VirtualAdcExit);