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, &reg);
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