1@page page_device_sensor Sensor Device 2 3# Introduction 4 5Sensors are an important part of the Internet of Things, and sensors in an IoT system are equivalent to the eyes of humans. Without eyes, human beings can not see and interpret the world around them. The same is true for the Internet of Things. 6 7Nowadays, with the development of IoT, a large number of sensors are available for developers to choose, such as Accelerometers, Magnetometers, Gyroscopes, Barometers/pressure senosrs, Hygrometers/humidity meters and so on. However, these sensors, manufactured by the world's leading semiconductor manufacturers, have increased market selectivity and made application development more difficult. Because different sensor manufacturers and sensors need their own unique drivers to run, developers need to write a device driver for each sensor, which can be difficult and time-consuming. In order to reduce the difficulty of application development and increase the reusability of sensor driver, we designed a Sensor device. 8 9The function of the Sensor device is to provide a unified operation interface for the upper layer and improve the reusability of the upper code. 10 11## Characteristics of the Sensor Device 12 13- **Interface:** Standard device interface (open/close/read/control) 14- **Work mode:** Supports polling, interrupts, three FIFO (First In, First Out) modes 15- **Power mode:** support four modes: power failure, common, low power consumption and high power consumption 16 17# Access Sensor Device 18 19The application accesses the sensor device through the I/O device management interface provided by RT-Thread. The related interfaces are as follows: 20 21| Functions | Description | 22| --------------------------- | ------------------------------------------------------------ | 23| rt_device_find() | Finding device handles based on device name of sensor device | 24| rt_device_open() | open sensor device | 25| rt_device_read() | read data | 26| rt_device_control() | control sensor device | 27| rt_device_set_rx_indicate() | setting reveive callback fuction | 28| rt_device_close() | close sensor device | 29 30## Find Sensor Device 31 32The application obtains the device handle according to the name of the sensor device, and then can operate the sensor device. The function of finding the device is as follows: 33 34```c 35rt_device_t rt_device_find(const char* name); 36``` 37 38| **Parameter** | **Description** | 39| ------------- | ------------------------------------------------------------ | 40| name | sensor device name | 41| **return** | —— | 42| handle | Finding the corresponding device returns the corresponding device handle | 43| RT_NULL | No corresponding device object was found | 44 45The use example is as follows: 46```c 47#define SENSOR_DEVICE_NAME "acce_st" /* sensor device name */ 48 49static rt_device_t sensor_dev; /* sensor device handle */ 50/* Find the sensor device according to the device name and get the device handle */ 51sensor_dev = rt_device_find(SENSOR_DEVICE_NAME); 52``` 53 54## Open Sensor Device 55 56Through the device handle, the application can open and close the device. When the device is opened, it will check whether the device has been initialized or not. If it is not initialized, it will call the initialization interface by default. Open the device through the following functions: 57 58```c 59rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags); 60``` 61 62| **Parameter** | **Description** | 63| ------------- | ------------------------------------------------------------ | 64| dev | device handle | 65| oflags | open mode flag | 66| **Return** | —— | 67| RT_EOK | open success | 68| -RT_EBUSY | If the RT_DEVICE_FLAG_STANDALONE parameter is included in the parameter specified at the time of device registration, the device will not be allowed to open repeatedly. | 69| -RT_EINVAL | Unsupported open mode | 70| other err | open failed | 71 72The oflags parameter supports the following parameters: 73 74```c 75#define RT_DEVICE_FLAG_RDONLY 0x001 /* Read-only mode for standard device, polling mode for corresponding sensors */ 76#define RT_DEVICE_FLAG_INT_RX 0x100 /* Interrupt Receiving Mode */ 77#define RT_DEVICE_FLAG_FIFO_RX 0x200 /* FIFO receiving mode */ 78``` 79 80There are three modes of receiving and sending sensor data: interrupt mode, polling mode and FIFO mode. When using these three modes, **only one of them can be chosen**. If the sensor's open parameter oflags does not specify the use of interrupt mode or FIFO mode, polling mode is used by default. 81 82FIFO transmission mode needs sensor hardware support, data is stored in hardware FIFO, which reads and stores multiple data simultaneously, which allows the CPU to do other operations while gathering data. This feature is very useful in low power mode. 83 84If the sensor uses FIFO receiving mode, the value of oflags is RT_DEVICE_FLAG_FIFO_RX. 85 86An example of turning on sensor devices in polling mode is as follows: 87 88```c 89#define SAMPLE_SENSOR_NAME "acce_st" /* sensor device name */ 90int main(void) 91{ 92 rt_device_t dev; 93 struct rt_sensor_data data; 94 95 /* find sensor device */ 96 dev = rt_device_find(SAMPLE_SENSOR_NAME); 97 /* Open sensor devices in read-only and polling mode */ 98 rt_device_open(dev, RT_DEVICE_FLAG_RDWR); 99 100 if (rt_device_read(dev, 0, &data, 1) == 1) 101 { 102 rt_kprintf("acce: x:%5d, y:%5d, z:%5d, timestamp:%5d\n", data.data.acce.x, data.data.acce.y, data.data.acce.z, data.timestamp); 103 } 104 rt_device_close(dev); 105 106 return RT_EOK; 107} 108``` 109 110## Control Sensor Device 111 112By command control words, the application program can configure the sensor device through the following functions: 113 114```c 115rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg); 116``` 117 118| **Parameter** | **Description** | 119| ------------- | ------------------------------------------------------------ | 120| dev | device handle | 121| cmd | command control word, see below for more details. | 122| arg | the parameters of command control word, see below for more details. | 123| **Return** | —— | 124| RT_EOK | success | 125| -RT_ENOSYS | failed,device is NULL | 126| other err | failed | 127 128`cmd` currently supports the following command control words: 129 130```c 131#define RT_SEN_CTRL_GET_ID (0) /* read device ID */ 132#define RT_SEN_CTRL_GET_INFO (1) /* get device information */ 133#define RT_SEN_CTRL_SET_RANGE (2) /* Setting the measuring range of the sensor */ 134#define RT_SEN_CTRL_SET_ODR (3) /* Setting the Output Rate of Sensor Data,unit is HZ */ 135#define RT_SEN_CTRL_SET_MODE (4) /* Setting up working mode */ 136#define RT_SEN_CTRL_SET_POWER (5) /* Setting up power mode */ 137#define RT_SEN_CTRL_SELF_TEST (6) /* selfcheck */ 138``` 139 140### Get device information 141 142```c 143struct rt_sensor_info info; 144rt_device_control(dev, RT_SEN_CTRL_GET_INFO, &info); 145LOG_I("vendor :%d", info.vendor); 146LOG_I("model :%s", info.model); 147LOG_I("unit :%d", info.unit); 148LOG_I("intf_type :%d", info.intf_type); 149LOG_I("period_min:%d", info.period_min); 150``` 151 152### Read Device ID 153 154```c 155rt_uint8_t reg = 0xFF; 156rt_device_control(dev, RT_SEN_CTRL_GET_ID, ®); 157LOG_I("device id: 0x%x!", reg); 158``` 159 160### Setting the measuring range of the sensor 161 162The unit that sets the measuring range of the sensor is the unit that is provided when the device is registered. 163 164```c 165rt_device_control(dev, RT_SEN_CTRL_SET_RANGE, (void *)1000); 166``` 167 168### Setting the Output Rate of Sensor Data 169 170Set the output rate to 100Hz and call the following interface. 171 172```c 173rt_device_control(dev, RT_SEN_CTRL_SET_ODR, (void *)100); 174``` 175 176### Setting up working mode 177 178```c 179/* Set the working mode to polling mode */ 180rt_device_control(dev, RT_SEN_CTRL_SET_MODE, (void *)RT_SEN_MODE_POLLING); 181/* Set working mode to interrupt mode */ 182rt_device_control(dev, RT_SEN_CTRL_SET_MODE, (void *)RT_SEN_MODE_INT); 183/* Set working mode to FIFO mode */ 184rt_device_control(dev, RT_SEN_CTRL_SET_MODE, (void *)RT_SEN_MODE_FIFO); 185``` 186 187### Setting up power mode 188 189```c 190/* Set power mode to power-off mode */ 191rt_device_control(dev, RT_SEN_CTRL_SET_POWER, (void *)RT_SEN_POWER_DOWN); 192/* Set power mode to normal mode */ 193rt_device_control(dev, RT_SEN_CTRL_SET_POWER, (void *)RT_SEN_POWER_NORMAL); 194/* Setting Power Mode to Low Power Consumption Mode */ 195rt_device_control(dev, RT_SEN_CTRL_SET_POWER, (void *)RT_SEN_POWER_LOW); 196/* Setting Power Mode to High Performance Mode */ 197rt_device_control(dev, RT_SEN_CTRL_SET_POWER, (void *)RT_SEN_POWER_HIGH); 198``` 199 200### Device self-inspection 201 202```c 203int test_res; 204/* Control equipment self-check and return the results. Returning RT_EOK indicates success of self-check and other values indicate failure of self-check. */ 205rt_device_control(dev, RT_SEN_CTRL_SELF_TEST, &test_res); 206``` 207 208## Setting Reveive Callback Fuction 209 210Data reception instructions can be set by following functions. When the sensor receives data, it notifies the upper application thread that data arrives: 211 212```c 213rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev,rt_size_t size)); 214``` 215 216| **Parameter** | **Description** | 217| ------------- | --------------------------------------------- | 218| dev | device handle | 219| rx_ind | Callback function pointer | 220| dev | device handle(parameter of callback function) | 221| size | buffer size(parameter of callback function) | 222| **Return** | —— | 223| RT_EOK | Successful setup | 224 225The callback function of the function is provided by the user. If the sensor is opened in interrupt mode, as the sensor receives data the callback function will be called. The data size of the buffer will be placed in the `size` parameter, and the sensor device handle will be placed in the `dev` parameter for users to obtain. 226 227Generally, receiving callback function can send a semaphore or event to inform sensor data processing thread that data arrives. The use example is as follows: 228 229```c 230#define SAMPLE_SENSOR_NAME "acce_st" /* sensor device name */ 231static rt_device_t dev; /* sensoe device handle*/ 232static struct rt_semaphore rx_sem; /* The semaphore used to receive messages */ 233 234/* Callback function for receiving data */ 235static rt_err_t sensor_input(rt_device_t dev, rt_size_t size) 236{ 237 /* When the sensor receives the data, it generates an interrupt, calls the callback function, and sends the semphore . */ 238 rt_sem_release(&rx_sem); 239 240 return RT_EOK; 241} 242 243static int sensor_sample(int argc, char *argv[]) 244{ 245 dev = rt_device_find(SAMPLE_SENSOR_NAME); 246 247 /* Open Sensor Device in Interrupt Receive and Poll Send Mode */ 248 rt_device_open(dev, RT_DEVICE_FLAG_INT_RX); 249 /* init semphore */ 250 rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO); 251 252 /* setting reveive callback function */ 253 rt_device_set_rx_indicate(dev, sensor_input); 254} 255 256``` 257 258## Read Data of Sensor Device 259 260The following functions can be called to read the data received by the sensor: 261 262```c 263rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size); 264``` 265 266| **Parameter** | **Description** | 267| ---------------------- | ------------------------------------------------------------ | 268| dev | device handle | 269| pos | Read data offset, sensor does not use this parameter | 270| buffer | Buffer pointer, read data will be saved in the buffer | 271| size | Size of read data | 272| **Return** | —— | 273| Real size of read data | Returns the number of read data | 274| 0 | The errno of the current thread needs to be read to determine the error status | 275 276The sensor uses the interrupt receiving mode and cooperates with the receiving callback function as follows: 277 278```c 279static rt_device_t dev; /* sensor device handle */ 280static struct rt_semaphore rx_sem; /* The semaphore used to receive messages */ 281 282/* Threads receiving data */ 283static void sensor_irq_rx_entry(void *parameter) 284{ 285 rt_device_t dev = parameter; 286 struct rt_sensor_data data; 287 rt_size_t res; 288 289 while (1) 290 { 291 rt_sem_take(rx_sem, RT_WAITING_FOREVER); 292 293 res = rt_device_read(dev, 0, &data, 1); 294 if (res == 1) 295 { 296 sensor_show_data(dev, &data); 297 } 298 } 299} 300 301``` 302 303The sensor uses FIFO receiving mode and cooperates with receiving callback function as follows: 304 305```c 306static rt_sem_t sensor_rx_sem = RT_NULL; 307rt_err_t rx_cb(rt_device_t dev, rt_size_t size) 308{ 309 rt_sem_release(sensor_rx_sem); 310 return 0; 311} 312static void sensor_fifo_rx_entry(void *parameter) 313{ 314 rt_device_t dev = parameter; 315 struct rt_sensor_data data; 316 rt_size_t res, i; 317 318 data = rt_malloc(sizeof(struct rt_sensor_data) * 32); 319 320 while (1) 321 { 322 rt_sem_take(sensor_rx_sem, RT_WAITING_FOREVER); 323 324 res = rt_device_read(dev, 0, data, 32); 325 for (i = 0; i < res; i++) 326 { 327 sensor_show_data(dev, &data[i]); 328 } 329 } 330} 331int main(void) 332{ 333 static rt_thread_t tid1 = RT_NULL; 334 rt_device_t dev; 335 struct rt_sensor_data data; 336 337 sensor_rx_sem = rt_sem_create("sen_rx_sem", 0, RT_IPC_FLAG_FIFO); 338 tid1 = rt_thread_create("sen_rx_thread", 339 sensor_fifo_rx_entry, dev, 340 1024, 341 15, 5); 342 if (tid1 != RT_NULL) 343 rt_thread_startup(tid1); 344 345 dev = rt_device_find("acce_st"); 346 rt_device_set_rx_indicate(dev, rx_cb); 347 rt_device_open(dev, RT_SEN_FLAG_FIFO); 348 return RT_EOK; 349} 350``` 351 352## Close Sensor Device 353 354When the application completes the sensor operation, the sensor device can be closed by the following functions: 355 356```c 357rt_err_t rt_device_close(rt_device_t dev); 358``` 359 360| **Parameter** | **Description** | 361| ------------- | ------------------------------------------------------------ | 362| dev | device handle | 363| **Return** | —— | 364| RT_EOK | The equipment was closed successfully. | 365| -RT_ERROR | The device has been completely shut down and cannot be closed repeatedly. | 366| other err | failed to close th device | 367 368Closing the device interface and opening the device interface should be used in pairs, opening the primary device should close the primary device, so that the device will be completely closed, otherwise the device is still in an open state. 369 370# Example Code for Sensor Device 371 372The specific use of sensor devices can be referred to the following sample code, the main steps of the sample code are as follows: 373 3741. Find the sensor device first and get the device handle. 375 3762. Open the sensor device by polling. 377 3783. Read the data five times in a row and print it out. 379 3804. Close the sensor device. 381 382This sample code is not limited to a specific BSP. According to the BSP registered sensor device, input different dev_name to run. 383 384```c 385/* 386 * Program List: This is a routine for sensor devices 387 * The routine exports the sensor_sample command to the control terminal 388 * Command Call Format:sensor_sample dev_name 389 * Command Interpretation: The second parameter of the command is the name of the sensor device to be used. 390 * Program function: Open the corresponding sensor, and then read the data five times in a row and print it out. 391*/ 392 393#include "sensor.h" 394 395static void sensor_show_data(rt_size_t num, rt_sensor_t sensor, struct rt_sensor_data *sensor_data) 396{ 397 switch (sensor->info.type) 398 { 399 case RT_SENSOR_CLASS_ACCE: 400 rt_kprintf("num:%3d, x:%5d, y:%5d, z:%5d, timestamp:%5d\n", num, sensor_data->data.acce.x, sensor_data->data.acce.y, sensor_data->data.acce.z, sensor_data->timestamp); 401 break; 402 case RT_SENSOR_CLASS_GYRO: 403 rt_kprintf("num:%3d, x:%8d, y:%8d, z:%8d, timestamp:%5d\n", num, sensor_data->data.gyro.x, sensor_data->data.gyro.y, sensor_data->data.gyro.z, sensor_data->timestamp); 404 break; 405 case RT_SENSOR_CLASS_MAG: 406 rt_kprintf("num:%3d, x:%5d, y:%5d, z:%5d, timestamp:%5d\n", num, sensor_data->data.mag.x, sensor_data->data.mag.y, sensor_data->data.mag.z, sensor_data->timestamp); 407 break; 408 case RT_SENSOR_CLASS_HUMI: 409 rt_kprintf("num:%3d, humi:%3d.%d%%, timestamp:%5d\n", num, sensor_data->data.humi / 10, sensor_data->data.humi % 10, sensor_data->timestamp); 410 break; 411 case RT_SENSOR_CLASS_TEMP: 412 rt_kprintf("num:%3d, temp:%3d.%dC, timestamp:%5d\n", num, sensor_data->data.temp / 10, sensor_data->data.temp % 10, sensor_data->timestamp); 413 break; 414 case RT_SENSOR_CLASS_BARO: 415 rt_kprintf("num:%3d, press:%5d, timestamp:%5d\n", num, sensor_data->data.baro, sensor_data->timestamp); 416 break; 417 case RT_SENSOR_CLASS_STEP: 418 rt_kprintf("num:%3d, step:%5d, timestamp:%5d\n", num, sensor_data->data.step, sensor_data->timestamp); 419 break; 420 default: 421 break; 422 } 423} 424 425static void sensor_sample(int argc, char **argv) 426{ 427 rt_device_t dev = RT_NULL; 428 struct rt_sensor_data data; 429 rt_size_t res, i; 430 431 /* Finding Sensor Devices in the System */ 432 dev = rt_device_find(argv[1]); 433 if (dev == RT_NULL) 434 { 435 rt_kprintf("Can't find device:%s\n", argv[1]); 436 return; 437 } 438 439 /* Open sensor devices in polling mode */ 440 if (rt_device_open(dev, RT_DEVICE_FLAG_RDWR) != RT_EOK) 441 { 442 rt_kprintf("open device failed!"); 443 return; 444 } 445 446 for (i = 0; i < 5; i++) 447 { 448 /* Read a data from a sensor */ 449 res = rt_device_read(dev, 0, &data, 1); 450 if (res != 1) 451 { 452 rt_kprintf("read data failed!size is %d", res); 453 } 454 else 455 { 456 sensor_show_data(i, (rt_sensor_t)dev, &data); 457 } 458 rt_thread_mdelay(100); 459 } 460 /* Close the sensor device */ 461 rt_device_close(dev); 462} 463MSH_CMD_EXPORT(sensor_sample, sensor device sample); 464``` 465 466