From 148afd95484e7a0958af022cfad75fe81f8147dc Mon Sep 17 00:00:00 2001 From: dongjiuzhu Date: Sun, 22 Nov 2020 16:04:37 +0800 Subject: [PATCH] driver/sensors: support custom type of sensor. For examples, the custom sensor could define: struct custem_event_s { uint64_t timestamp; int16_t adc[8]; }; struct sensor_lowerhalf_s g_lower = { .buffer_size = 1024, }; sensor_custom_register(lower, "/dev/sensor/custom0", sizeof(struct custem_event_s)); Signed-off-by: dongjiuzhu --- drivers/sensors/sensor.c | 114 ++++++++++++++++++++++--------- include/nuttx/sensors/sensor.h | 119 ++++++++++++++++++++++++--------- 2 files changed, 169 insertions(+), 64 deletions(-) diff --git a/drivers/sensors/sensor.c b/drivers/sensors/sensor.c index 64d26a303c..8145b31041 100644 --- a/drivers/sensors/sensor.c +++ b/drivers/sensors/sensor.c @@ -69,6 +69,7 @@ struct sensor_upperhalf_s FAR struct pollfd *fds[CONFIG_SENSORS_NPOLLWAITERS]; FAR struct sensor_lowerhalf_s *lower; /* the handle of lower half driver */ struct circbuf_s buffer; /* The circular buffer of sensor device */ + uint8_t esize; /* The element size of circular buffer */ uint8_t crefs; /* Number of times the device has been opened */ sem_t exclsem; /* Manages exclusive access to file operations */ sem_t buffersem; /* Wakeup user waiting for data in circular buffer */ @@ -98,6 +99,7 @@ static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, static const struct sensor_info g_sensor_info[] = { + {0, NULL}, {sizeof(struct sensor_event_accel), "accel"}, {sizeof(struct sensor_event_mag), "mag"}, {sizeof(struct sensor_event_gyro), "gyro"}, @@ -172,7 +174,6 @@ static int sensor_open(FAR struct file *filep) FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; - size_t bytes; uint8_t tmp; int ret; @@ -194,8 +195,7 @@ static int sensor_open(FAR struct file *filep) { /* Initialize sensor buffer */ - bytes = ROUNDUP(lower->buffer_size, g_sensor_info[lower->type].esize); - ret = circbuf_init(&upper->buffer, NULL, bytes); + ret = circbuf_init(&upper->buffer, NULL, lower->buffer_size); if (ret < 0) { goto err; @@ -243,7 +243,6 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; ssize_t ret; - size_t bytes; if (!buffer || !len) { @@ -319,9 +318,7 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, circbuf_size(&upper->buffer) > lower->buffer_size && circbuf_used(&upper->buffer) <= lower->buffer_size) { - bytes = ROUNDUP(lower->buffer_size, - g_sensor_info[lower->type].esize); - ret = circbuf_resize(&upper->buffer, bytes); + ret = circbuf_resize(&upper->buffer, lower->buffer_size); } } @@ -404,10 +401,8 @@ static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) /* Adjust length of buffer in batch mode */ bytes = ROUNDUP(ROUNDUP(*val, upper->interval) / - upper->interval * - g_sensor_info[lower->type].esize + - lower->buffer_size, - g_sensor_info[lower->type].esize); + upper->interval * upper->esize + + lower->buffer_size, upper->esize); ret = circbuf_resize(&upper->buffer, bytes); } @@ -417,7 +412,7 @@ static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) case SNIOC_GET_NEVENTBUF: { - *val = lower->buffer_size / g_sensor_info[lower->type].esize; + *val = lower->buffer_size / upper->esize; } break; @@ -425,11 +420,8 @@ static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { if (*val != 0) { - lower->buffer_size = ROUNDUP(*val, - g_sensor_info[lower->type].esize); - bytes = ROUNDUP(lower->buffer_size, - g_sensor_info[lower->type].esize); - ret = circbuf_resize(&upper->buffer, bytes); + lower->buffer_size = ROUNDUP(*val, upper->esize); + ret = circbuf_resize(&upper->buffer, lower->buffer_size); if (ret >= 0) { *val = lower->buffer_size; @@ -613,15 +605,53 @@ static void sensor_notify_event(FAR void *priv) int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) { - FAR struct sensor_upperhalf_s *upper; char path[DEVNAME_MAX]; + + DEBUGASSERT(lower != NULL); + + snprintf(path, DEVNAME_MAX, DEVNAME_FMT, + g_sensor_info[lower->type].name, + lower->uncalibrated ? DEVNAME_UNCAL : "", + devno); + return sensor_custom_register(lower, path, + g_sensor_info[lower->type].esize); +} + +/**************************************************************************** + * Name: sensor_custom_register + * + * Description: + * This function binds an instance of a "lower half" Sensor driver with the + * "upper half" Sensor device and registers that device so that can be used + * by application code. + * + * You can register the character device type by specific path and esize. + * This API corresponds to the sensor_custom_unregister. + * + * Input Parameters: + * dev - A pointer to an instance of lower half sensor driver. This + * instance is bound to the sensor driver and must persists as long + * as the driver persists. + * path - The user specifies path of device. ex: /dev/sensor/xxx. + * esize - The element size of intermediate circular buffer. + * + * Returned Value: + * OK if the driver was successfully register; A negated errno value is + * returned on any failure. + * + ****************************************************************************/ + +int sensor_custom_register(FAR struct sensor_lowerhalf_s *lower, + FAR const char *path, uint8_t esize) +{ + FAR struct sensor_upperhalf_s *upper; int ret = -EINVAL; DEBUGASSERT(lower != NULL); - if (lower->type >= SENSOR_TYPE_COUNT) + if (lower->type >= SENSOR_TYPE_COUNT || !esize) { - snerr("ERROR: Type is invalid\n"); + snerr("ERROR: type is invalid\n"); return ret; } @@ -637,6 +667,7 @@ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) /* Initialize the upper-half data structure */ upper->lower = lower; + upper->esize = esize; nxsem_init(&upper->exclsem, 0, 1); nxsem_init(&upper->buffersem, 0, 0); @@ -651,7 +682,11 @@ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) { if (!lower->buffer_size) { - lower->buffer_size = g_sensor_info[lower->type].esize; + lower->buffer_size = esize; + } + else + { + lower->buffer_size = ROUNDUP(lower->buffer_size, esize); } lower->push_event = sensor_push_event; @@ -659,14 +694,10 @@ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) else { lower->notify_event = sensor_notify_event; + lower->buffer_size = 0; } - snprintf(path, DEVNAME_MAX, DEVNAME_FMT, - g_sensor_info[lower->type].name, - lower->uncalibrated ? DEVNAME_UNCAL : "", - devno); sninfo("Registering %s\n", path); - ret = register_driver(path, &g_sensor_fops, 0666, upper); if (ret) { @@ -700,18 +731,39 @@ drv_err: void sensor_unregister(FAR struct sensor_lowerhalf_s *lower, int devno) { - FAR struct sensor_upperhalf_s *upper; char path[DEVNAME_MAX]; + snprintf(path, DEVNAME_MAX, DEVNAME_FMT, + g_sensor_info[lower->type].name, + lower->uncalibrated ? DEVNAME_UNCAL : "", + devno); + sensor_custom_unregister(lower, path); +} + +/**************************************************************************** + * Name: sensor_custom_unregister + * + * Description: + * This function unregister character node and release all resource about + * upper half driver. This API corresponds to the sensor_custom_register. + * + * Input Parameters: + * dev - A pointer to an instance of lower half sensor driver. This + * instance is bound to the sensor driver and must persists as long + * as the driver persists. + * path - The user specifies path of device, ex: /dev/sensor/xxx + ****************************************************************************/ + +void sensor_custom_unregister(FAR struct sensor_lowerhalf_s *lower, + FAR const char *path) +{ + FAR struct sensor_upperhalf_s *upper; + DEBUGASSERT(lower != NULL); DEBUGASSERT(lower->priv != NULL); upper = lower->priv; - snprintf(path, DEVNAME_MAX, DEVNAME_FMT, - g_sensor_info[lower->type].name, - lower->uncalibrated ? DEVNAME_UNCAL : "", - devno); sninfo("UnRegistering %s\n", path); unregister_driver(path); diff --git a/include/nuttx/sensors/sensor.h b/include/nuttx/sensors/sensor.h index 14bc9e0735..23d155b0a5 100644 --- a/include/nuttx/sensors/sensor.h +++ b/include/nuttx/sensors/sensor.h @@ -40,142 +40,151 @@ /* sensor type definition */ +/* Custom Sensor + * Some special sensor whose event size is not fixed or dynamically change, + * are called sensor of custom type. You should treat its events as byte + * streams and use sensor_custom_register to register character device + * with specific path, ex: "/dev/sensor/custom_dummy". + */ + +#define SENSOR_TYPE_CUSTOM 0 + /* Accelerometer * All values are in SI units (m/s^2), and measure the acceleration of the * device minus the acceleration dut to gravity. */ -#define SENSOR_TYPE_ACCELEROMETER 0 +#define SENSOR_TYPE_ACCELEROMETER 1 /* Magneric Field * All values are in micro-Tesla (uT) and measure the geomagnetic field * in X, Y and Z axis. */ -#define SENSOR_TYPE_MAGNETIC_FIELD 1 +#define SENSOR_TYPE_MAGNETIC_FIELD 2 /* Gyroscope * All values are in radians/second and measure the rate of rotation around * the X, Y and Z axis. */ -#define SENSOR_TYPE_GYROSCOPE 2 +#define SENSOR_TYPE_GYROSCOPE 3 /* Ambient Light * The ambient light sensor value is returned in SI units lux. */ -#define SENSOR_TYPE_LIGHT 3 +#define SENSOR_TYPE_LIGHT 4 /* Barometer - * All values are in hectopascal (hPa) and measure the athmospheric pressure - * we can calculate altitude by perssure. + * All values are in hectopascal (hPa) and measure the athmospheric pressure. + * You can calculate altitude by perssure. */ -#define SENSOR_TYPE_BAROMETER 4 +#define SENSOR_TYPE_BAROMETER 5 /* Proximity * The values correspond to the distance to the nearest * object in centimeters. */ -#define SENSOR_TYPE_PROXIMITY 5 +#define SENSOR_TYPE_PROXIMITY 6 /* Relative Humidity * A relative humidity sensor measure relative ambient air humidity and * return a value in percent. */ -#define SENSOR_TYPE_RELATIVE_HUMIDITY 6 +#define SENSOR_TYPE_RELATIVE_HUMIDITY 7 /* Ambient Temperature * The ambient (room) temperature in degree Celsius */ -#define SENSOR_TYPE_AMBIENT_TEMPERATURE 7 +#define SENSOR_TYPE_AMBIENT_TEMPERATURE 8 /* RGB * We use these values of RGB to weighted to obtain the color of LED. * These values is in unit percent. */ -#define SENSOR_TYPE_RGB 8 +#define SENSOR_TYPE_RGB 9 /* Hall * All values are in bool type (0 or 1) and it often is used to as switch. * A values of 1 indicates that switch on. */ -#define SENSOR_TYPE_HALL 9 +#define SENSOR_TYPE_HALL 10 /* IR (Infrared Ray) * This sensor can detect a human approach and outputs a signal from * interrupt pins. This sensor value is in lux. */ -#define SENSOR_TYPE_IR 10 +#define SENSOR_TYPE_IR 11 /* GPS * A sensor of this type returns gps data. Include year, month, day, * hour, minutes, seconds, altitude, longitude, latitude. */ -#define SENSOR_TYPE_GPS 11 +#define SENSOR_TYPE_GPS 12 /* Ultraviolet light sensor * This sensor can identify the UV index in ambient light help people * to effectively protect themselves from sunburns, cancer or eye damage. * This value range is 0 - 15. */ -#define SENSOR_TYPE_ULTRAVIOLET 12 +#define SENSOR_TYPE_ULTRAVIOLET 13 /* Noise Loudness * A sensor of this type returns the loudness of noise in SI units (db) */ -#define SENSOR_TYPE_NOISE 13 +#define SENSOR_TYPE_NOISE 14 /* PM25 * A sensor of this type returns the content of pm2.5 in the air * This value is in SI units (ug/m^3) */ -#define SENSOR_TYPE_PM25 14 +#define SENSOR_TYPE_PM25 15 /* PM1P0 * A sensor of this type returns the content of pm1.0 in the air * This value is in SI units (ug/m^3) */ -#define SENSOR_TYPE_PM1P0 15 +#define SENSOR_TYPE_PM1P0 16 /* PM10 * A sensor of this type returns the content of pm10 in the air * This value is in SI units (ug/m^3) */ -#define SENSOR_TYPE_PM10 16 +#define SENSOR_TYPE_PM10 17 /* CO2 * A sensor of this type returns the content of CO2 in the air * This vaule is in units (ppm-part per million). */ -#define SENSOR_TYPE_CO2 17 +#define SENSOR_TYPE_CO2 18 /* HCHO * The HCHO pollution is an important indicator of household air * pollution. This value is in units (ppm-part per million). */ -#define SENSOR_TYPE_HCHO 18 +#define SENSOR_TYPE_HCHO 19 /* TVOC (total volatile organic compounds) * The indoor TVOC is cause indoor air pollution is one of the * main reasons why. This value is in units (ppb-part per billion). */ -#define SENSOR_TYPE_TVOC 19 +#define SENSOR_TYPE_TVOC 20 /* PH * The acid-base degree describes the strength of the aqueous @@ -184,21 +193,21 @@ * pH<7 is acidic, and pH>7 is alkaline. */ -#define SENSOR_TYPE_PH 20 +#define SENSOR_TYPE_PH 21 /* Dust * A sensor of this type returns the content of dust in the air * values is in ug/m^3. */ -#define SENSOR_TYPE_DUST 21 +#define SENSOR_TYPE_DUST 22 /* Heart Rate * A sensor of this type returns the current heart rate. * Current heart rate is in beats per minute (BPM). */ -#define SENSOR_TYPE_HEART_RATE 22 +#define SENSOR_TYPE_HEART_RATE 23 /* Heart Beat * A sensor of this type returns an event evetytime @@ -206,11 +215,11 @@ * to the positive peak in the QRS complex of and ECG signal. */ -#define SENSOR_TYPE_HEART_BEAT 23 +#define SENSOR_TYPE_HEART_BEAT 24 /* The total number of sensor */ -#define SENSOR_TYPE_COUNT 24 +#define SENSOR_TYPE_COUNT 25 /**************************************************************************** * Inline Functions @@ -532,7 +541,7 @@ struct sensor_ops_s /************************************************************************** * Name: control * - * In this method, we allow user to set some special config for the sensor, + * With this method, the user can set some special config for the sensor, * such as changing the custom mode, setting the custom resolution, reset, * etc, which are all parsed and implemented by lower half driver. * @@ -648,9 +657,10 @@ extern "C" * "upper half" Sensor device and registers that device so that can be used * by application code. * - * We will register the chararter device by node name format based on the + * You can register the character device by node name format based on the * type of sensor. Multiple types of the same type are distinguished by - * numbers. eg: accel0, accel1 + * numbers. eg: accel0, accel1. This type of sensor must be less than + * SENSOR_TYPE_COUNT. This API corresponds to the sensor_unregister. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This @@ -668,21 +678,64 @@ extern "C" int sensor_register(FAR struct sensor_lowerhalf_s *dev, int devno); /**************************************************************************** - * Name: sensor_unregister + * Name: sensor_custom_register * * Description: - * This function unregister character node and release all resource about - * upper half driver. + * This function binds an instance of a "lower half" Sensor driver with the + * "upper half" Sensor device and registers that device so that can be used + * by application code. + * + * You can register the character device type by specific path and esize. + * This API corresponds to the sensor_custom_unregister. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persist as long * as the driver persists. + * path - The user specifies path of device. ex: /dev/sensor/xxx. + * esize - The element size of intermediate circular buffer. + * + * Returned Value: + * OK if the driver was successfully register; A negated errno value is + * returned on any failure. + * + ****************************************************************************/ + +int sensor_custom_register(FAR struct sensor_lowerhalf_s *dev, + FAR const char *path, uint8_t esize); + +/**************************************************************************** + * Name: sensor_unregister + * + * Description: + * This function unregisters character node and releases all resource from + * upper half driver. This API corresponds to the sensor_register. + * + * Input Parameters: + * dev - A pointer to an instance of lower half sensor driver. This + * instance is bound to the sensor driver and must persists as long + * as the driver persists. * devno - The user specifies which device of this type, from 0. ****************************************************************************/ void sensor_unregister(FAR struct sensor_lowerhalf_s *dev, int devno); +/**************************************************************************** + * Name: sensor_custom_unregister + * + * Description: + * This function unregisters character node and releases all resource from + * upper half driver. This API corresponds to the sensor_custom_register. + * + * Input Parameters: + * dev - A pointer to an instance of lower half sensor driver. This + * instance is bound to the sensor driver and must persists as long + * as the driver persists. + * path - The user specifies path of device, ex: /dev/sensor/xxx + ****************************************************************************/ + +void sensor_custom_unregister(FAR struct sensor_lowerhalf_s *dev, + FAR const char *path); #undef EXTERN #if defined(__cplusplus) }