فهرست منبع

【增加】虚拟传感器

张世争 5 سال پیش
والد
کامیت
225a28d704
19فایلهای تغییر یافته به همراه2630 افزوده شده و 1 حذف شده
  1. 45 1
      README.md
  2. 52 0
      SConscript
  3. BIN
      docs/img/01.png
  4. BIN
      docs/img/02.png
  5. BIN
      docs/img/03.png
  6. BIN
      docs/img/04.png
  7. 196 0
      v_accelerometer.c
  8. 194 0
      v_barometer.c
  9. 194 0
      v_force.c
  10. 198 0
      v_gyroscope.c
  11. 194 0
      v_heartRate.c
  12. 194 0
      v_humidity.c
  13. 195 0
      v_light.c
  14. 198 0
      v_magnetometer.c
  15. 194 0
      v_noise.c
  16. 194 0
      v_proximity.c
  17. 194 0
      v_stepcounter.c
  18. 194 0
      v_temperature.c
  19. 194 0
      v_tvoc.c

+ 45 - 1
README.md

@@ -1,2 +1,46 @@
 # vsensor
-虚拟传感器
+
+rt-thread虚拟传感器,基于RT-Thread Sensor框架,模拟传感器设备基本的功能。
+
+## 传感器列表
+
+
+
+| 编号 | 传感器名称    | 备注         |
+| ---- | ------------- | ------------ |
+| 1    | Accelerometer | 加速度传感器 |
+| 2    | Gyroscope     | 陀螺仪       |
+| 3    | Magnetometer  | 磁传感器     |
+| 4    | Temperature   | 温度传感器   |
+| 5    | Humidity      | 湿度传感器   |
+| 6    | Barometer     | 气压计       |
+| 7    | Light         | 光感         |
+| 8    | Proximity     | 距离传感器   |
+| 9    | HeartRate     | 心率传感器   |
+| 10   | TVOC          | 血氧         |
+| 11   | Noise         | 噪声传感器   |
+| 12   | StepCounter   | 计步传感器   |
+| 13   | Force         | 力传感器     |
+
+
+
+
+## 使用说明
+
+* 通过menuconfig,使能虚拟传感器
+* 使能单个或多个传感器
+
+![图片01](docs/img/01.png)
+
+![图片01](docs/img/02.png)
+
+![图片01](docs/img/03.png)
+
+![图片01](docs/img/04.png)
+
+## 维护地址
+```c
+https://github.com/RT-Thread-packages/vsensor.git
+RT-Thread 团队
+```
+

+ 52 - 0
SConscript

@@ -0,0 +1,52 @@
+Import('RTT_ROOT')
+Import('rtconfig')
+from building import *
+
+src = []
+cwd     = GetCurrentDir()
+list = os.listdir(cwd)
+CPPPATH = [cwd, str(Dir('#'))]
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_ACCE']):
+    src += Glob('v_accelerometer.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_BARO']):
+    src += Glob('v_barometer.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_FORCE']):
+    src += Glob('v_force.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_GYRO']):
+    src += Glob('v_gyroscope.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_HR']):
+    src += Glob('v_heartRate.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_HUMI']):
+    src += Glob('v_humidity.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_LIGHT']):
+    src += Glob('v_light.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_MAG']):
+    src += Glob('v_magnetometer.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_NOISE']):
+    src += Glob('v_noise.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_PROX']):
+    src += Glob('v_proximity.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_STEP']):
+    src += Glob('v_stepcounter.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_TEMP']):
+    src += Glob('v_temperature.c')
+
+if GetDepend(['PKG_USING_VIRTUAL_SENSOR_TVOC']):
+    src += Glob('v_tvoc.c')
+
+group = DefineGroup('vsensor', src, depend = ['PKG_USING_VIRTUAL_SENSOR'], CPPPATH = CPPPATH)
+
+Return('group')
+

BIN
docs/img/01.png


BIN
docs/img/02.png


BIN
docs/img/03.png


BIN
docs/img/04.png


+ 196 - 0
v_accelerometer.c

@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_ACCE
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_acce"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_ACCE_ID
+{
+    SENS_ACCE_01 = 0, //Accelerometer
+    SENS_ACCE_MAX,
+};
+
+#define SENS_BUS_NAME                       "sens_bus"
+#define SENS_ACCE_01_SENSOR_ID              (RT_SENSOR_CLASS_ACCE + 0x10)
+
+struct sens_acce
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_acce sens_acce_tbl[SENS_ACCE_MAX] =
+{
+    {V_SENS_ACCE_DEV_NAME,            0x00 }, /* Accelerometer */
+};
+
+static struct rt_sensor_info acce_info_tbl[SENS_ACCE_MAX] =
+{
+    {RT_SENSOR_CLASS_ACCE,  RT_SENSOR_VENDOR_BOSCH,   RT_NULL,    RT_SENSOR_UNIT_MG,      RT_SENSOR_INTF_SPI,     2048,   -2048,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_ACCE_01:
+        chip_id = SENS_ACCE_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_acce_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t acce_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = acce_info_tbl[SENS_ACCE_01].range_max - acce_info_tbl[SENS_ACCE_01].range_min;
+    data->type = RT_SENSOR_CLASS_TVOC;
+    data->data.acce.x = rand() % max_range + acce_info_tbl[SENS_ACCE_01].range_min;
+    data->data.acce.y = rand() % max_range + acce_info_tbl[SENS_ACCE_01].range_min;
+    data->data.acce.z = rand() % max_range + acce_info_tbl[SENS_ACCE_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d,%d,%d", __func__, data->data.acce.x,
+        data->data.acce.y, data->data.acce.z);
+    return RT_EOK;
+}
+
+static rt_err_t acce_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_acce_tbl[SENS_ACCE_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {acce_sensor_fetch_data, acce_sensor_control},
+};
+
+int rt_vd_sens_acce_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_ACCE_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = acce_info_tbl[index].type;
+        sensor_dat->info.vendor = acce_info_tbl[index].vendor;
+        sensor_dat->info.model = acce_info_tbl[index].model;
+        sensor_dat->info.unit = acce_info_tbl[index].unit;
+        sensor_dat->info.intf_type = acce_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = acce_info_tbl[index].range_max;
+        sensor_dat->info.range_min = acce_info_tbl[index].range_min;
+        sensor_dat->info.period_min = acce_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_acce_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_acce_init);
+
+#endif
+

+ 194 - 0
v_barometer.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_BARO
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_baro"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_BARO_ID
+{
+    SENS_BARO_01 = 0, //Barometer
+    SENS_BARO_MAX,
+};
+
+#define SENS_BUS_NAME                   "sens_bus"
+#define SENS_BARO_01_SENSOR_ID          (RT_SENSOR_CLASS_BARO + 0x10)
+
+struct sens_baro
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_baro sens_baro_tbl[SENS_BARO_MAX] =
+{
+    {V_SENS_BARO_DEV_NAME,  0x00 }, /* Barometer */
+};
+
+static struct rt_sensor_info baro_info_tbl[SENS_BARO_MAX] =
+{
+    {RT_SENSOR_CLASS_BARO,  RT_SENSOR_VENDOR_BOSCH,   RT_NULL,    RT_SENSOR_UNIT_PA,      RT_SENSOR_INTF_SPI,     2048,   0,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_BARO_01:
+        chip_id = SENS_BARO_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_baro_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t baro_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = baro_info_tbl[SENS_BARO_01].range_max - baro_info_tbl[SENS_BARO_01].range_min;
+    data->type = RT_SENSOR_CLASS_BARO;
+    data->data.baro = rand() % max_range + baro_info_tbl[SENS_BARO_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d", __func__, data->data.baro);
+
+    return RT_EOK;
+}
+
+static rt_err_t baro_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_baro_tbl[SENS_BARO_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {baro_sensor_fetch_data, baro_sensor_control},
+};
+
+int rt_vd_sens_baro_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_BARO_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = baro_info_tbl[index].type;
+        sensor_dat->info.vendor = baro_info_tbl[index].vendor;
+        sensor_dat->info.model = baro_info_tbl[index].model;
+        sensor_dat->info.unit = baro_info_tbl[index].unit;
+        sensor_dat->info.intf_type = baro_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = baro_info_tbl[index].range_max;
+        sensor_dat->info.range_min = baro_info_tbl[index].range_min;
+        sensor_dat->info.period_min = baro_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_baro_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_baro_init);
+
+#endif
+

+ 194 - 0
v_force.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_FORCE
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_force"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_FORCE_ID
+{
+    SENS_FORCE_01 = 0, //Force
+    SENS_FORCE_MAX,
+};
+
+#define SENS_BUS_NAME                   "sens_bus"
+#define SENS_FORCE_01_SENSOR_ID         (RT_SENSOR_CLASS_FORCE + 0x10)
+
+struct sens_force
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_force sens_force_tbl[SENS_FORCE_MAX] =
+{
+    {V_SENS_FORCE_DEV_NAME,               0x00 }, /* Force */
+};
+
+static struct rt_sensor_info force_info_tbl[SENS_FORCE_MAX] =
+{
+    {RT_SENSOR_CLASS_FORCE,  RT_SENSOR_VENDOR_STM,   RT_NULL,    RT_SENSOR_UNIT_MN,      RT_SENSOR_INTF_SPI,     255,   0,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_FORCE_01:
+        chip_id = SENS_FORCE_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_force_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t force_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = force_info_tbl[SENS_FORCE_01].range_max - force_info_tbl[SENS_FORCE_01].range_min;
+    data->type = RT_SENSOR_CLASS_FORCE;
+    data->data.force = rand() % max_range + force_info_tbl[SENS_FORCE_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d", __func__, data->data.force);
+
+    return RT_EOK;
+}
+
+static rt_err_t force_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_force_tbl[SENS_FORCE_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {force_sensor_fetch_data, force_sensor_control},
+};
+
+int rt_vd_sens_force_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_FORCE_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = force_info_tbl[index].type;
+        sensor_dat->info.vendor = force_info_tbl[index].vendor;
+        sensor_dat->info.model = force_info_tbl[index].model;
+        sensor_dat->info.unit = force_info_tbl[index].unit;
+        sensor_dat->info.intf_type = force_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = force_info_tbl[index].range_max;
+        sensor_dat->info.range_min = force_info_tbl[index].range_min;
+        sensor_dat->info.period_min = force_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_force_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_force_init);
+
+#endif
+

+ 198 - 0
v_gyroscope.c

@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_GYRO
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_gyro"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_GYRO_ID
+{
+    SENS_GYRO_01 = 0, //Gyroscope
+    SENS_GYRO_MAX,
+};
+
+#define SENS_BUS_NAME                   "sens_bus"
+#define SENS_GYRO_01_SENSOR_ID          (RT_SENSOR_CLASS_GYRO + 0x10)
+
+struct sens_gyro
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_gyro sens_gyro_tbl[SENS_GYRO_MAX] =
+{
+    {V_SENS_GYRO_DEV_NAME,           0x00 }, /* Gyroscope */
+};
+
+static struct rt_sensor_info gyro_info_tbl[SENS_GYRO_MAX] =
+{
+    {RT_SENSOR_CLASS_GYRO,  RT_SENSOR_VENDOR_BOSCH,   RT_NULL,    RT_SENSOR_UNIT_MDPS,      RT_SENSOR_INTF_I2C,     1024,   -1024,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_GYRO_01:
+        chip_id = SENS_GYRO_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_gyro_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t gyro_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = gyro_info_tbl[SENS_GYRO_01].range_max - gyro_info_tbl[SENS_GYRO_01].range_min;
+    data->type = RT_SENSOR_CLASS_GYRO;
+
+    data->data.gyro.x = rand() % max_range + gyro_info_tbl[SENS_GYRO_01].range_min;
+    data->data.gyro.y = rand() % max_range + gyro_info_tbl[SENS_GYRO_01].range_min;
+    data->data.gyro.z = rand() % max_range + gyro_info_tbl[SENS_GYRO_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d,%d,%d", __func__, data->data.gyro.x,
+        data->data.gyro.y, data->data.gyro.z);
+
+    return RT_EOK;
+}
+
+static rt_err_t gyro_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_gyro_tbl[SENS_GYRO_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {gyro_sensor_fetch_data, gyro_sensor_control},
+};
+
+int rt_vd_sens_gyro_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_GYRO_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = gyro_info_tbl[index].type;
+        sensor_dat->info.vendor = gyro_info_tbl[index].vendor;
+        sensor_dat->info.model = gyro_info_tbl[index].model;
+        sensor_dat->info.unit = gyro_info_tbl[index].unit;
+        sensor_dat->info.intf_type = gyro_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = gyro_info_tbl[index].range_max;
+        sensor_dat->info.range_min = gyro_info_tbl[index].range_min;
+        sensor_dat->info.period_min = gyro_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_gyro_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_gyro_init);
+
+#endif
+

+ 194 - 0
v_heartRate.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_HR
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_hrate"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_HR_ID
+{
+    SENS_HR_01 = 0, //HeartRate
+    SENS_HR_MAX,
+};
+
+#define SENS_BUS_NAME                   "sens_bus"
+#define SENS_HR_01_SENSOR_ID            (RT_SENSOR_CLASS_HR + 0x10)
+
+struct sens_hr
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_hr sens_hr_tbl[SENS_HR_MAX] =
+{
+    {V_SENS_HR_DEV_NAME,    0x00 }, /* HeartRate */
+};
+
+static struct rt_sensor_info hr_info_tbl[SENS_HR_MAX] =
+{
+    {RT_SENSOR_CLASS_HR,  RT_SENSOR_VENDOR_STM,   RT_NULL,    RT_SENSOR_UNIT_BPM,      RT_SENSOR_INTF_UART,     200,   0,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_HR_01:
+        chip_id = SENS_HR_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_hr_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t hr_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = hr_info_tbl[SENS_HR_01].range_max - hr_info_tbl[SENS_HR_01].range_min;
+    data->type = RT_SENSOR_CLASS_HR;
+    data->data.hr = rand() % max_range + hr_info_tbl[SENS_HR_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d", __func__, data->data.hr);
+
+    return RT_EOK;
+}
+
+static rt_err_t hr_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_hr_tbl[SENS_HR_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {hr_sensor_fetch_data, hr_sensor_control},
+};
+
+int rt_vd_sens_hr_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_HR_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = hr_info_tbl[index].type;
+        sensor_dat->info.vendor = hr_info_tbl[index].vendor;
+        sensor_dat->info.model = hr_info_tbl[index].model;
+        sensor_dat->info.unit = hr_info_tbl[index].unit;
+        sensor_dat->info.intf_type = hr_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = hr_info_tbl[index].range_max;
+        sensor_dat->info.range_min = hr_info_tbl[index].range_min;
+        sensor_dat->info.period_min = hr_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_hr_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_hr_init);
+
+#endif
+

+ 194 - 0
v_humidity.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_HUMI
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_humi"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_HUMI_ID
+{
+    SENS_HUMI_01 = 0, //Humidity
+    SENS_HUMI_MAX,
+};
+
+#define SENS_BUS_NAME                       "sens_bus"
+#define SENS_HUMI_01_SENSOR_ID                 (RT_SENSOR_CLASS_HUMI + 0x10)
+
+struct sens_humi
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_humi sens_humi_tbl[SENS_HUMI_MAX] =
+{
+    {V_SENS_HUMI_DEV_NAME,            0x00 }, /* Humidity */
+};
+
+static struct rt_sensor_info humi_info_tbl[SENS_HUMI_MAX] =
+{
+    {RT_SENSOR_CLASS_HUMI,  RT_SENSOR_VENDOR_DALLAS,   RT_NULL,    RT_SENSOR_UNIT_PERMILLAGE,      RT_SENSOR_INTF_ONEWIRE,     100,   0,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_HUMI_01:
+        chip_id = SENS_HUMI_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_humi_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t humi_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = humi_info_tbl[SENS_HUMI_01].range_max - humi_info_tbl[SENS_HUMI_01].range_min;
+    data->type = RT_SENSOR_CLASS_HUMI;
+    data->data.humi = rand() % max_range + humi_info_tbl[SENS_HUMI_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d", __func__, data->data.humi);
+
+    return RT_EOK;
+}
+
+static rt_err_t humi_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_humi_tbl[SENS_HUMI_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {humi_sensor_fetch_data, humi_sensor_control},
+};
+
+int rt_vd_sens_humi_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_HUMI_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = humi_info_tbl[index].type;
+        sensor_dat->info.vendor = humi_info_tbl[index].vendor;
+        sensor_dat->info.model = humi_info_tbl[index].model;
+        sensor_dat->info.unit = humi_info_tbl[index].unit;
+        sensor_dat->info.intf_type = humi_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = humi_info_tbl[index].range_max;
+        sensor_dat->info.range_min = humi_info_tbl[index].range_min;
+        sensor_dat->info.period_min = humi_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_humi_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_humi_init);
+
+#endif
+

+ 195 - 0
v_light.c

@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_LIGHT
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_li"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_LIGHT_ID
+{
+    SENS_LIGHT_01 = 0, //Light
+    SENS_LIGHT_MAX,
+};
+
+#define SENS_BUS_NAME                       "sens_bus"
+#define SENS_LIGHT_01_SENSOR_ID                (RT_SENSOR_CLASS_LIGHT + 0x10)
+
+struct sens_light
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_light sens_light_tbl[SENS_LIGHT_MAX] =
+{
+    {V_SENS_LIGHT_DEV_NAME,               0x00 }, /* Light */
+};
+
+static struct rt_sensor_info light_info_tbl[SENS_LIGHT_MAX] =
+{
+    {RT_SENSOR_CLASS_LIGHT,  RT_SENSOR_VENDOR_BOSCH,   RT_NULL,    RT_SENSOR_UNIT_LUX,      RT_SENSOR_INTF_SPI,     2048000,   0,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_LIGHT_01:
+        chip_id = SENS_LIGHT_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_light_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t light_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = light_info_tbl[SENS_LIGHT_01].range_max - light_info_tbl[SENS_LIGHT_01].range_min;
+    data->type = RT_SENSOR_CLASS_LIGHT;
+    data->data.light = rand() % max_range + light_info_tbl[SENS_LIGHT_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+
+    LOG_D("%s:%d", __func__, data->data.light);
+
+    return RT_EOK;
+}
+
+static rt_err_t light_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_light_tbl[SENS_LIGHT_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {light_sensor_fetch_data, light_sensor_control},
+};
+
+int rt_vd_sens_light_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_LIGHT_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = light_info_tbl[index].type;
+        sensor_dat->info.vendor = light_info_tbl[index].vendor;
+        sensor_dat->info.model = light_info_tbl[index].model;
+        sensor_dat->info.unit = light_info_tbl[index].unit;
+        sensor_dat->info.intf_type = light_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = light_info_tbl[index].range_max;
+        sensor_dat->info.range_min = light_info_tbl[index].range_min;
+        sensor_dat->info.period_min = light_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_light_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_light_init);
+
+#endif
+

+ 198 - 0
v_magnetometer.c

@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_MAG
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_mag"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_MAG_ID
+{
+    SENS_MAG_01 = 0, //Magnetometer
+    SENS_MAG_MAX,
+};
+
+#define SENS_BUS_NAME                       "sens_bus"
+#define SENS_MAG_01_SENSOR_ID                  (RT_SENSOR_CLASS_MAG + 0x10)
+
+struct sens_mag
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_mag sens_mag_tbl[SENS_MAG_MAX] =
+{
+    {V_SENS_MAG_DEV_NAME,        0x00 }, /* Magnetometer */
+};
+
+static struct rt_sensor_info mag_info_tbl[SENS_MAG_MAX] =
+{
+    {RT_SENSOR_CLASS_MAG,   RT_SENSOR_VENDOR_BOSCH,   RT_NULL,    RT_SENSOR_UNIT_MGAUSS,      RT_SENSOR_INTF_SPI,     360,   0,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_MAG_01:
+        chip_id = SENS_MAG_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_mag_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t mag_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = mag_info_tbl[SENS_MAG_01].range_max - mag_info_tbl[SENS_MAG_01].range_min;
+    data->type = RT_SENSOR_CLASS_MAG;
+    data->data.mag.x = rand() % max_range + mag_info_tbl[SENS_MAG_01].range_min;
+    data->data.mag.y = rand() % max_range + mag_info_tbl[SENS_MAG_01].range_min;
+    data->data.mag.z = rand() % max_range + mag_info_tbl[SENS_MAG_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+
+    LOG_D("%s:%d,%d,%d", __func__, data->data.mag.x,
+        data->data.mag.y, data->data.mag.z);
+
+    return RT_EOK;
+}
+
+static rt_err_t mag_sensor_control(struct rt_sensor_device *sensor, int cmd, void *args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_mag_tbl[SENS_MAG_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {mag_sensor_fetch_data, mag_sensor_control},
+};
+
+int rt_vd_sens_mag_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_MAG_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = mag_info_tbl[index].type;
+        sensor_dat->info.vendor = mag_info_tbl[index].vendor;
+        sensor_dat->info.model = mag_info_tbl[index].model;
+        sensor_dat->info.unit = mag_info_tbl[index].unit;
+        sensor_dat->info.intf_type = mag_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = mag_info_tbl[index].range_max;
+        sensor_dat->info.range_min = mag_info_tbl[index].range_min;
+        sensor_dat->info.period_min = mag_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_mag_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_mag_init);
+
+#endif
+

+ 194 - 0
v_noise.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_NOISE
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_noise"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_NOISE_ID
+{
+    SENS_NOISE_01 = 0, //NOISE
+    SENS_NOISE_MAX,
+};
+
+#define SENS_BUS_NAME                       "sens_bus"
+#define SENS_NOISE_01_SENSOR_ID                (RT_SENSOR_CLASS_NOISE + 0x10)
+
+struct sens_noise
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_noise sens_noise_tbl[SENS_NOISE_MAX] =
+{
+    {V_SENS_NOISE_DEV_NAME,               0x00 }, /* NOISE */
+};
+
+static struct rt_sensor_info noise_info_tbl[SENS_NOISE_MAX] =
+{
+    {RT_SENSOR_CLASS_NOISE,  RT_SENSOR_VENDOR_STM,   RT_NULL,    RT_SENSOR_UNIT_ONE,      RT_SENSOR_INTF_I2C,     254,   -254,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_NOISE_01:
+        chip_id = SENS_NOISE_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_noise_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t noise_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = noise_info_tbl[SENS_NOISE_01].range_max - noise_info_tbl[SENS_NOISE_01].range_min;
+    data->type = RT_SENSOR_CLASS_NOISE;
+    data->data.noise = rand() % max_range + noise_info_tbl[SENS_NOISE_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d", __func__, data->data.noise);
+
+    return RT_EOK;
+}
+
+static rt_err_t noise_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_noise_tbl[SENS_NOISE_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {noise_sensor_fetch_data, noise_sensor_control},
+};
+
+int rt_vd_sens_noise_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_NOISE_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = noise_info_tbl[index].type;
+        sensor_dat->info.vendor = noise_info_tbl[index].vendor;
+        sensor_dat->info.model = noise_info_tbl[index].model;
+        sensor_dat->info.unit = noise_info_tbl[index].unit;
+        sensor_dat->info.intf_type = noise_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = noise_info_tbl[index].range_max;
+        sensor_dat->info.range_min = noise_info_tbl[index].range_min;
+        sensor_dat->info.period_min = noise_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_noise_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_noise_init);
+
+#endif
+

+ 194 - 0
v_proximity.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_PROX
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_prox"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_PROX_ID
+{
+    SENS_PROX_01 = 0, //Proximity
+    SENS_PROX_MAX,
+};
+
+#define SENS_BUS_NAME               "sens_bus"
+#define SENS_PROX_01_SENSOR_ID      (RT_SENSOR_CLASS_PROXIMITY + 0x10)
+
+struct sens_prox
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_prox sens_prox_tbl[SENS_PROX_MAX] =
+{
+    {V_SENS_PROX_DEV_NAME,           0x00 }, /* Proximity */
+};
+
+static struct rt_sensor_info prox_info_tbl[SENS_PROX_MAX] =
+{
+    {RT_SENSOR_CLASS_PROXIMITY,  RT_SENSOR_VENDOR_STM,   RT_NULL,    RT_SENSOR_UNIT_MM,      RT_SENSOR_INTF_SPI,     2048,   0,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_PROX_01:
+        chip_id = SENS_PROX_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_prox_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t prox_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = prox_info_tbl[SENS_PROX_01].range_max - prox_info_tbl[SENS_PROX_01].range_min;
+    data->type = RT_SENSOR_CLASS_HUMI;
+    data->data.proximity = rand() % max_range + prox_info_tbl[SENS_PROX_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d", __func__, data->data.proximity);
+
+    return RT_EOK;
+}
+
+static rt_err_t prox_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_prox_tbl[SENS_PROX_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {prox_sensor_fetch_data, prox_sensor_control},
+};
+
+int rt_vd_sens_prox_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_PROX_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = prox_info_tbl[index].type;
+        sensor_dat->info.vendor = prox_info_tbl[index].vendor;
+        sensor_dat->info.model = prox_info_tbl[index].model;
+        sensor_dat->info.unit = prox_info_tbl[index].unit;
+        sensor_dat->info.intf_type = prox_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = prox_info_tbl[index].range_max;
+        sensor_dat->info.range_min = prox_info_tbl[index].range_min;
+        sensor_dat->info.period_min = prox_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_prox_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_prox_init);
+
+#endif
+

+ 194 - 0
v_stepcounter.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_STEP
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_step"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_STEP_ID
+{
+    SENS_STEP_01 = 0, //StepCounter
+    SENS_STEP_MAX,
+};
+
+#define SENS_BUS_NAME                       "sens_bus"
+#define SENS_STEP_01_SENSOR_ID                 (RT_SENSOR_CLASS_STEP + 0x10)
+
+struct sens_step
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_step sens_step_tbl[SENS_STEP_MAX] =
+{
+    {V_SENS_STEP_DEV_NAME,                0x00 }, /* StepCounter */
+};
+
+static struct rt_sensor_info step_info_tbl[SENS_STEP_MAX] =
+{
+    {RT_SENSOR_CLASS_STEP,  RT_SENSOR_VENDOR_STM,   RT_NULL,    RT_SENSOR_UNIT_ONE,      RT_SENSOR_INTF_I2C,     2048000,   0,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_STEP_01:
+        chip_id = SENS_STEP_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_step_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t step_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = step_info_tbl[SENS_STEP_01].range_max - step_info_tbl[SENS_STEP_01].range_min;
+    data->type = RT_SENSOR_CLASS_STEP;
+    data->data.step = rand() % max_range + step_info_tbl[SENS_STEP_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d", __func__, data->data.step);
+
+    return RT_EOK;
+}
+
+static rt_err_t step_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_step_tbl[SENS_STEP_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {step_sensor_fetch_data, step_sensor_control},
+};
+
+int rt_vd_sens_step_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_STEP_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = step_info_tbl[index].type;
+        sensor_dat->info.vendor = step_info_tbl[index].vendor;
+        sensor_dat->info.model = step_info_tbl[index].model;
+        sensor_dat->info.unit = step_info_tbl[index].unit;
+        sensor_dat->info.intf_type = step_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = step_info_tbl[index].range_max;
+        sensor_dat->info.range_min = step_info_tbl[index].range_min;
+        sensor_dat->info.period_min = step_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_step_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_step_init);
+
+#endif
+

+ 194 - 0
v_temperature.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_TEMP
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_temp"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_TEMP_ID
+{
+    SENS_TEMP_01 = 0, //Temperature
+    SENS_TEMP_MAX,
+};
+
+#define SENS_BUS_NAME                       "sens_bus"
+#define SENS_TEMP_01_SENSOR_ID                 (RT_SENSOR_CLASS_TEMP + 0x10)
+
+struct sens_temp
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_temp sens_temp_tbl[SENS_TEMP_MAX] =
+{
+    {V_SENS_TEMP_DEV_NAME,         0x00 }, /* Temperature */
+};
+
+static struct rt_sensor_info temp_info_tbl[SENS_TEMP_MAX] =
+{
+    {RT_SENSOR_CLASS_TEMP,  RT_SENSOR_VENDOR_DALLAS,   RT_NULL,    RT_SENSOR_UNIT_DCELSIUS,      RT_SENSOR_INTF_ONEWIRE,     125,   -45,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_TEMP_01:
+        chip_id = SENS_TEMP_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_temp_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t temp_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = temp_info_tbl[SENS_TEMP_01].range_max - temp_info_tbl[SENS_TEMP_01].range_min;
+    data->type = RT_SENSOR_CLASS_TEMP;
+    data->data.temp = rand() % max_range + temp_info_tbl[SENS_TEMP_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d", __func__, data->data.temp);
+
+    return RT_EOK;
+}
+
+static rt_err_t temp_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_temp_tbl[SENS_TEMP_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {temp_sensor_fetch_data, temp_sensor_control},
+};
+
+int rt_vd_sens_temp_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_TEMP_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = temp_info_tbl[index].type;
+        sensor_dat->info.vendor = temp_info_tbl[index].vendor;
+        sensor_dat->info.model = temp_info_tbl[index].model;
+        sensor_dat->info.unit = temp_info_tbl[index].unit;
+        sensor_dat->info.intf_type = temp_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = temp_info_tbl[index].range_max;
+        sensor_dat->info.range_min = temp_info_tbl[index].range_min;
+        sensor_dat->info.period_min = temp_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_temp_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_temp_init);
+
+#endif
+

+ 194 - 0
v_tvoc.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-19     zhangsz      add virtual sensor device
+ */
+
+#include <rtthread.h>
+
+#ifdef PKG_USING_VIRTUAL_SENSOR_TVOC
+
+#include "sensor.h"
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME    "v_tvoc"
+#define DBG_LEVEL           DBG_LOG
+#include <rtdbg.h>
+
+enum SENS_TVOC_ID
+{
+    SENS_TVOC_01 = 0, //TVOC
+    SENS_TVOC_MAX,
+};
+
+#define SENS_BUS_NAME                       "sens_bus"
+#define SENS_TVOC_01_SENSOR_ID                 (RT_SENSOR_CLASS_TVOC + 0x10)
+
+struct sens_tvoc
+{
+    char* dev_name;
+    rt_uint8_t sens_id;
+};
+
+static struct sens_tvoc sens_tvoc_tbl[SENS_TVOC_MAX] =
+{
+    {V_SENS_TVOC_DEV_NAME,                0x00 }, /* TVOC */
+};
+
+static struct rt_sensor_info tvoc_info_tbl[SENS_TVOC_MAX] =
+{
+    {RT_SENSOR_CLASS_TVOC,  RT_SENSOR_VENDOR_STM,   RT_NULL,    RT_SENSOR_UNIT_ONE,      RT_SENSOR_INTF_SPI,     4096,   0,   1 },
+};
+
+static rt_uint8_t sensor_get_id(rt_uint8_t sens_index)
+{
+    rt_uint8_t chip_id = 0x00;
+
+    switch (sens_index)
+    {
+    case SENS_TVOC_01:
+        chip_id = SENS_TVOC_01_SENSOR_ID;
+        break;
+    default:
+        break;
+    }
+
+    return chip_id;
+}
+
+static int sensor_init(rt_uint8_t index)
+{
+    sens_tvoc_tbl[index].sens_id = sensor_get_id(index);
+
+    return RT_EOK;
+}
+
+static void* _sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index)
+{
+    if (sensor_init(index) != RT_EOK)
+    {
+        LOG_E("%s:error!", __func__);
+    }
+
+    return 0;
+}
+
+static rt_err_t _sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr)
+{
+    LOG_D("%s:odr=%d", __func__, odr);
+    return RT_EOK;
+}
+static rt_err_t _sensor_set_range(rt_sensor_t sensor, rt_uint16_t range)
+{
+    LOG_D("%s:range=%d", __func__, range);
+    return RT_EOK;
+}
+
+static rt_err_t _sensor_set_power(rt_sensor_t sensor, rt_uint8_t power)
+{
+    rt_int8_t rslt = 0;
+    LOG_D("%s:power=%d", __func__, power);
+    return rslt;
+}
+
+static rt_size_t tvoc_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t len)
+{
+    struct rt_sensor_data* data = buf;
+    rt_int16_t max_range = 0;
+
+    max_range = tvoc_info_tbl[SENS_TVOC_01].range_max - tvoc_info_tbl[SENS_TVOC_01].range_min;
+    data->type = RT_SENSOR_CLASS_TVOC;
+    data->data.tvoc = rand() % max_range + tvoc_info_tbl[SENS_TVOC_01].range_min;
+    data->timestamp = rt_sensor_get_ts();
+    LOG_D("%s:%d", __func__, data->data.tvoc);
+
+    return RT_EOK;
+}
+
+static rt_err_t tvoc_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args)
+{
+    rt_err_t result = RT_EOK;
+
+    switch (cmd)
+    {
+    case RT_SENSOR_CTRL_GET_ID:
+        *(rt_uint8_t*)args = sens_tvoc_tbl[SENS_TVOC_01].sens_id;
+        break;
+    case RT_SENSOR_CTRL_SET_ODR:
+        result = _sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff);
+        break;
+    case RT_SENSOR_CTRL_SET_RANGE:
+        result = _sensor_set_range(sensor, (rt_uint32_t)args);
+        break;
+    case RT_SENSOR_CTRL_SET_POWER:
+        result = _sensor_set_power(sensor, (rt_uint32_t)args & 0xff);
+        break;
+    case RT_SENSOR_CTRL_SELF_TEST:
+        /* TODO */
+        result = -RT_EINVAL;
+        break;
+    default:
+        return -RT_EINVAL;
+    }
+    return result;
+}
+
+static struct rt_sensor_ops sensor_ops[] =
+{
+    {tvoc_sensor_fetch_data, tvoc_sensor_control},
+};
+
+int rt_vd_sens_tvoc_init(void)
+{
+    rt_int8_t result;
+    rt_uint8_t index = 0;
+    rt_sensor_t sensor_dat = RT_NULL;
+    struct rt_sensor_config cfg;
+
+    cfg.intf.dev_name = SENS_BUS_NAME;
+    cfg.intf.user_data = RT_NULL;
+    cfg.irq_pin.pin = RT_PIN_NONE;
+
+    for (index = 0; index < SENS_TVOC_MAX; index++)
+    {
+        _sensor_create(&cfg.intf, index);
+        sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device));
+        if (sensor_dat == RT_NULL)
+        {
+            LOG_E("rt_hw_sens_init:rt_calloc err!");
+            return -RT_ERROR;
+        }
+
+        sensor_dat->info.type = tvoc_info_tbl[index].type;
+        sensor_dat->info.vendor = tvoc_info_tbl[index].vendor;
+        sensor_dat->info.model = tvoc_info_tbl[index].model;
+        sensor_dat->info.unit = tvoc_info_tbl[index].unit;
+        sensor_dat->info.intf_type = tvoc_info_tbl[index].intf_type;
+        sensor_dat->info.range_max = tvoc_info_tbl[index].range_max;
+        sensor_dat->info.range_min = tvoc_info_tbl[index].range_min;
+        sensor_dat->info.period_min = tvoc_info_tbl[index].period_min;
+
+        rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config));
+        sensor_dat->ops = &sensor_ops[index];
+
+        result = rt_hw_sensor_register(sensor_dat, sens_tvoc_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL);
+        if (result != RT_EOK)
+        {
+            LOG_E("device register err code: %d", result);
+            rt_free(sensor_dat);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_vd_sens_tvoc_init);
+
+#endif
+