First commit XiUOS

This commit is contained in:
xuetest
2021-04-28 17:49:18 +08:00
commit 6001051eb7
1331 changed files with 433955 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
menu "Perception"
menuconfig PERCEPTION_SENSORDEVICE
bool "Using sensor devices"
default n
if PERCEPTION_SENSORDEVICE
menuconfig PERCEPTION_CO2
bool "Using CO2 sensor device"
default n
if PERCEPTION_CO2
source "$KERNEL_DIR/framework/perception/co2/Kconfig"
endif
menuconfig PERCEPTION_PM
bool "Using PM sensor device"
default n
if PERCEPTION_PM
source "$KERNEL_DIR/framework/perception/pm/Kconfig"
endif
menuconfig PERCEPTION_VOICE
bool "Using voice sensor device"
default n
if PERCEPTION_VOICE
source "$KERNEL_DIR/framework/perception/voice/Kconfig"
endif
menuconfig PERCEPTION_TEMPERATURE
bool "Using temperature sensor device"
default n
if PERCEPTION_TEMPERATURE
source "$KERNEL_DIR/framework/perception/temperature/Kconfig"
endif
menuconfig PERCEPTION_HUMIDITY
bool "Using humidity sensor device"
default n
if PERCEPTION_HUMIDITY
source "$KERNEL_DIR/framework/perception/humidity/Kconfig"
endif
endif
endmenu

View File

@@ -0,0 +1,25 @@
ifeq ($(CONFIG_PERCEPTION_SENSORDEVICE),y)
SRC_FILES := sensor.c
endif
ifeq ($(CONFIG_PERCEPTION_CO2),y)
SRC_DIR += co2
endif
ifeq ($(CONFIG_PERCEPTION_PM),y)
SRC_DIR += pm
endif
ifeq ($(CONFIG_PERCEPTION_VOICE),y)
SRC_DIR += voice
endif
ifeq ($(CONFIG_PERCEPTION_TEMPERATURE),y)
SRC_DIR += temperature
endif
ifeq ($(CONFIG_PERCEPTION_HUMIDITY),y)
SRC_DIR += humidity
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,192 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>XiUOS传感器框架</title>
<style>
</style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/markdown.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/highlight.css">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', system-ui, 'Ubuntu', 'Droid Sans', sans-serif;
font-size: 14px;
line-height: 1.6;
}
</style>
<style>
.task-list-item { list-style-type: none; } .task-list-item-checkbox { margin-left: -20px; vertical-align: middle; }
</style>
</head>
<body class="vscode-light">
<h1 id="xiuos传感器框架">XiUOS传感器框架</h1>
<p>多数嵌入式操作系统对传感器的抽象采用以物理传感器设备为中心的方式,在应用开发时无法绕过传感器设备的多样性,进而增加了传感器应用的开发难度和周期。这种抽象带来的缺陷在面对一些可以同时采集多种物理量的传感器(如温湿度传感器)时尤为突出,因为应用开发者不得不考虑每种传感器设备的采集数据的能力。</p>
<p>XiUOS的传感器框架以用户为中心采用了以物理量为中心的抽象方式在开发应用时只需要考虑所需感知的物理量种类无需把重点放在实际采集物理量的传感器设备。这种抽象方式有效地隐藏了底层传感器设备的硬件细节对外提供统一的数据采集接口可以简化传感器应用与驱动的开发。为实现以物理量为中心的抽象传感器框架对传感器设备进行两层抽象</p>
<ul>
<li>一个物理传感器测量一种物理量的能力ability被抽象为一个SensorQuantity结构</li>
<li>一个物理传感器本身被抽象为一个SensorDevice结构</li>
</ul>
<p>其中SensorQuantity被设计为可以采用类似面向对象的方法、针对不同物理量扩展其数据成员与接口从而为众多不同性质的物理量实现统一的管理架构。在应用开发的过程中只需要使用对应物理量的SensorQuantity实例无需关心传感器的硬件细节从而实现数据采样功能与底层硬件的解耦。</p>
<p>从关联关系上来看一个SensorQuantity对应一个SensorDevice一个SensorDevice对应一个或多个SensorQuantity。例如对于一个可以测量温度与湿度的传感器设备该设备唯一对应一个SensorDevice结构而该设备测量温度与湿度的能力分别对应一个SensorQuantity结构。两种数据结构的具体定义如下。</p>
<h2 id="struct-sensorquantity结构">struct SensorQuantity结构</h2>
<pre><code class="language-c"><div><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorQuantity</span> {</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> name[NAME_NUM_MAX]; <span class="hljs-comment">/* name of the sensor quantity instance */</span>
<span class="hljs-keyword">enum</span> SensorQuantityType type; <span class="hljs-comment">/* type of data the sensor collects, such as CO2 concentration */</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorDevice</span> *<span class="hljs-title">sdev</span>;</span> <span class="hljs-comment">/* corresponding sensor device */</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SysDoubleLinklistNode</span> <span class="hljs-title">link</span>;</span> <span class="hljs-comment">/* link list node */</span>
};
</div></code></pre>
<p>name成员是一个可读的名字用于唯一标识一个SensorQuantity结构。</p>
<p>type成员表示该SensorQuantity可测量的物理量用一个枚举变量表示</p>
<pre><code class="language-c"><div><span class="hljs-keyword">enum</span> SensorQuantityType {
SENSOR_QUANTITY_CO2 = <span class="hljs-number">0</span>, <span class="hljs-comment">/* CO2 concentration */</span>
SENSOR_QUANTITY_TEMP, <span class="hljs-comment">/* temperature */</span>
SENSOR_QUANTITY_HUMI, <span class="hljs-comment">/* humidity */</span>
<span class="hljs-comment">/* ...... */</span>
SENSOR_QUANTITY_END,
};
</div></code></pre>
<p>sdev成员表示该SensorQuantity所属的SensorDevice结构其具体定义在下文给出。</p>
<p>最后在系统中每种物理量的SensorQuantity被分别组织成不同双链表如二氧化碳浓度SensorQuantity链表、温度SensorQuantity链表等使用的链表节点即为link成员。</p>
<h2 id="struct-sensordevice结构">struct SensorDevice结构</h2>
<pre><code class="language-c"><div><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorDevice</span> {</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> name[NAME_NUM_MAX]; <span class="hljs-comment">/* name of the sensor device */</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorProductInfo</span> <span class="hljs-title">info</span>;</span> <span class="hljs-comment">/* sensor model info, such as vendor name and model name */</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorOps</span> <span class="hljs-title">ops</span>;</span> <span class="hljs-comment">/* filesystem-like APIs for data transferring */</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorInterface</span> <span class="hljs-title">interface</span>;</span> <span class="hljs-comment">/* physical interface for transferring data */</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SysDoubleLinklistNode</span> <span class="hljs-title">link</span>;</span> <span class="hljs-comment">/* link list node */</span>
};
</div></code></pre>
<p>name成员记录传感器设备在系统中的名字用于唯一标识一个SensorDevice结构</p>
<p>info成员记录传感器设备的一些属性信息包括传感器的能力ability、厂家名vendor与型号product_model其中ability用一个位图表示该传感器设备可以测量的物理量</p>
<pre><code class="language-c"><div><span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> SENSOR_ABILITY_CO2 ((uint32_t)(1 &lt;&lt; SENSOR_QUANTITY_CO2))</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> SENSOR_ABILITY_TEMP ((uint32_t)(1 &lt;&lt; SENSOR_QUANTITY_TEMP))</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> SENSOR_ABILITY_HUMI ((uint32_t)(1 &lt;&lt; SENSOR_QUANTITY_HUMI))</span>
<span class="hljs-comment">/* ...... */</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorProductInfo</span> {</span>
<span class="hljs-keyword">uint32_t</span> ability; <span class="hljs-comment">/* bitwise OR of SENSOR_ABILITY_XXX */</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *vendor;
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *product_model;
};
</div></code></pre>
<p>ops成员包含统一的、类似文件系统的API用于对传感器进行实际的数据读写。在使用一个传感器前后需要打开open/关闭close该传感器read、write分别用与从传感器接收数据与向传感器发送数据ioctl用于配置传感器属性如波特率</p>
<pre><code class="language-c"><div><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorOps</span> {</span>
<span class="hljs-keyword">int</span> (*open)(struct SensorDevice *sdev);
<span class="hljs-keyword">void</span> (*close)(struct SensorDevice *sdev);
<span class="hljs-keyword">int</span> (*read)(struct SensorDevice *sdev, <span class="hljs-keyword">void</span> *buf, <span class="hljs-keyword">size_t</span> len);
<span class="hljs-keyword">int</span> (*write)(struct SensorDevice *sdev, <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span> *buf, <span class="hljs-keyword">size_t</span> len);
<span class="hljs-keyword">int</span> (*ioctl)(struct SensorDevice *sdev, <span class="hljs-keyword">int</span> cmd, <span class="hljs-keyword">void</span> *arg);
};
</div></code></pre>
<p>interface成员表示用于与传感器进行通信的总线设备</p>
<pre><code class="language-c"><div><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorInterface</span> {</span>
<span class="hljs-keyword">device_t</span> bus_device;
};
</div></code></pre>
<p>最后系统中所有注册过的传感器设备被组织成一个双链表即link成员。</p>
<h2 id="传感器框架驱动开发">传感器框架驱动开发</h2>
<p>以二氧化碳传感器为例。传感器框架针对每个具体的物理量将SensorQuantity进行扩充采用类似面向对象的手段添加其他必要成员</p>
<pre><code class="language-c"><div><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorQuantityCo2</span> {</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorQuantity</span> <span class="hljs-title">parent</span>;</span> <span class="hljs-comment">/* inherit from SensorQuantity */</span>
<span class="hljs-keyword">uint32_t</span> (*read_concentration)(struct SensorQuantityCo2 *quant);
<span class="hljs-keyword">uint32_t</span> last_value; <span class="hljs-comment">/* last measured value */</span>
<span class="hljs-keyword">uint32_t</span> min_value; <span class="hljs-comment">/* minimum measured value */</span>
<span class="hljs-keyword">uint32_t</span> max_value; <span class="hljs-comment">/* maximum measured value */</span>
<span class="hljs-keyword">uint32_t</span> min_std; <span class="hljs-comment">/* national standard: minimum */</span>
<span class="hljs-keyword">uint32_t</span> max_std; <span class="hljs-comment">/* national standard: maximum */</span>
};
</div></code></pre>
<p>实现SensorOps中的数据通信API具体实现细节取决于传感器型号无法实现的API可以置为NULL</p>
<pre><code class="language-c"><div><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorOps</span> <span class="hljs-title">co2_example_ops</span> = {</span>
.open = co2_example_open;
.close = co2_example_close;
.read = co2_example_read;
.write = <span class="hljs-literal">NULL</span>;
.ioctl = co2_example_ioctl;
};
</div></code></pre>
<p>实现SensorQuantityCo2中的read_concentration接口该接口用于读取当前空气中的二氧化碳浓度。在实现过程中可以使用SensorOps中的接口与传感器进行通信。</p>
<p>最后将传感器设备添加到传感器框架。分别填充SensorDevice与对应物理量的SensorQuantity结构二氧化碳即为SensorQuantityCo2)并依次使用SensorDeviceRegister和SensorQuantityRegister函数将其注册到传感器框架</p>
<pre><code class="language-c"><div><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">SensorDeviceRegister</span><span class="hljs-params">(struct SensorDevice *sdev)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">SensorQuantityRegister</span><span class="hljs-params">(struct SensorQuantity *quant)</span></span>;
<span class="hljs-keyword">extern</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorOps</span> <span class="hljs-title">co2_example_ops</span>;</span>
<span class="hljs-function"><span class="hljs-keyword">extern</span> uint32_t <span class="hljs-title">co2_example_read_concentration</span><span class="hljs-params">(struct SensorQuantityCo2 *quant)</span></span>;
<span class="hljs-comment">/* declare SensorDevice and SensorQuantityCo2 objects */</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorDevice</span> <span class="hljs-title">co2_example_sdev</span>;</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorQuantityCo2</span> <span class="hljs-title">co2_example_quant</span>;</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">register_co2_sensor</span><span class="hljs-params">()</span>
</span>{
<span class="hljs-comment">/* initialize and register the SensorDevice object */</span>
<span class="hljs-built_in">memset</span>(&amp;co2_example_sdev, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(SensorDevice));
co2_example_sdev.name = <span class="hljs-string">"sensor1"</span>;
co2_example_sdev.info.ability |= SENSOR_ABILITY_CO2;
co2_example_sdev.info.vendor = <span class="hljs-string">"xxx"</span>;
co2_example_sdev.info.product_model = <span class="hljs-string">"yyy"</span>;
co2_example_sdev.ops = &amp;co2_example_ops;
co2_example_sdev.interface.bus_device = DeviceFind(<span class="hljs-string">"uart1"</span>);
SensorDeviceRegister(&amp;co2_example_sdev);
<span class="hljs-comment">/* initialize and register the SensorQuantity object */</span>
<span class="hljs-built_in">memset</span>(&amp;co2_example_quant, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(SensorQuantityCo2));
co2_example_quant.parent.name = <span class="hljs-string">"co2_1"</span>;
co2_example_quant.parent.type = SENSOR_QUANTITY_CO2;
co2_example_quant.parent.sdev = &amp;co2_example_sdev;
co2_example_quant.read_concentration = co2_example_read_concentration;
SensorQuantityRegister((struct SensorQuantity *)&amp;co2_example_quant);
}
</div></code></pre>
<h2 id="传感器框架的使用">传感器框架的使用</h2>
<p>传感器应用开发者使用传感器框架提供的API操作传感器传感器API可以分为通用API与物理量特有API。通用API用于传感器的获取、打开与关闭物理量特有API用于传感器的数据采样。以二氧化碳传感器为例</p>
<pre><code class="language-c"><div><span class="hljs-comment">/* generic API: find a sensor quantity instance by its name */</span>
<span class="hljs-function">struct SensorQuantity *<span class="hljs-title">SensorQuantityFind</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *name)</span></span>;
<span class="hljs-comment">/* generic API: open/close a sensor quantity instance */</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">SensorQuantityOpen</span><span class="hljs-params">(struct SensorQuantity *quant)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">SensorQuantityClose</span><span class="hljs-params">(struct SensorQuantity *quant)</span></span>;
<span class="hljs-comment">/* CO2 API: get current CO2 concentration reading (in ppm unit) */</span>
<span class="hljs-keyword">uint32_t</span> SensorCo2Read(struct SensorQuantityCo2 *quant);
</div></code></pre>
<p>在获取数据前,需要先获取并打开要使用的传感器;传感器打开后可以随时对传感器数据进行读取;使用完毕后,须关闭传感器。完整的使用过程示例如下:</p>
<pre><code class="language-c"><div><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span> *argv[])</span>
</span>{
<span class="hljs-keyword">int</span> ret;
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorQuantity</span> *<span class="hljs-title">quant</span>;</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SensorQuantityCo2</span> *<span class="hljs-title">co2_quant</span>;</span>
<span class="hljs-comment">/* get the CO2 sensor quantity instance */</span>
quant = SensorQuantityFind(<span class="hljs-string">"co2_1"</span>);
CHECK(quant-&gt;type == SENSOR_QUANTITY_CO2);
<span class="hljs-comment">/* open the CO2 sensor quantity instance */</span>
co2_quant = (struct SensorQuantityCo2 *)quant;
ret = SensorQuantityOpen(quant);
CHECK(ret == EOK);
<span class="hljs-comment">/* read CO2 concentration for 5 times, just for demonstration */</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++)
KPrintf(<span class="hljs-string">"Current CO2 concentration is %u ppm\n"</span>, SensorCo2Read(co2_quant));
SensorQuantityClose(quant);
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</div></code></pre>
</body>
</html>

View File

@@ -0,0 +1,194 @@
# XiUOS传感器框架
多数嵌入式操作系统对传感器的抽象采用以物理传感器设备为中心的方式,在应用开发时无法绕过传感器设备的多样性,进而增加了传感器应用的开发难度和周期。这种抽象带来的缺陷在面对一些可以同时采集多种物理量的传感器(如温湿度传感器)时尤为突出,因为应用开发者不得不考虑每种传感器设备的采集数据的能力。
XiUOS的传感器框架以用户为中心采用了以物理量为中心的抽象方式在开发应用时只需要考虑所需感知的物理量种类无需把重点放在实际采集物理量的传感器设备。这种抽象方式有效地隐藏了底层传感器设备的硬件细节对外提供统一的数据采集接口可以简化传感器应用与驱动的开发。为实现以物理量为中心的抽象传感器框架对传感器设备进行两层抽象
* 一个物理传感器测量一种物理量的能力ability被抽象为一个SensorQuantity结构
* 一个物理传感器本身被抽象为一个SensorDevice结构
其中SensorQuantity被设计为可以采用类似面向对象的方法、针对不同物理量扩展其数据成员与接口从而为众多不同性质的物理量实现统一的管理架构。在应用开发的过程中只需要使用对应物理量的SensorQuantity实例无需关心传感器的硬件细节从而实现数据采样功能与底层硬件的解耦。
从关联关系上来看一个SensorQuantity对应一个SensorDevice一个SensorDevice对应一个或多个SensorQuantity。例如对于一个可以测量温度与湿度的传感器设备该设备唯一对应一个SensorDevice结构而该设备测量温度与湿度的能力分别对应一个SensorQuantity结构。两种数据结构的具体定义如下。
## struct SensorQuantity结构
```c
struct SensorQuantity {
const char name[NAME_NUM_MAX]; /* name of the sensor quantity instance */
enum SensorQuantityType type; /* type of data the sensor collects, such as CO2 concentration */
struct SensorDevice *sdev; /* corresponding sensor device */
struct SysDoubleLinklistNode link; /* link list node */
};
```
name成员是一个可读的名字用于唯一标识一个SensorQuantity结构。
type成员表示该SensorQuantity可测量的物理量用一个枚举变量表示
```c
enum SensorQuantityType {
SENSOR_QUANTITY_CO2 = 0, /* CO2 concentration */
SENSOR_QUANTITY_TEMP, /* temperature */
SENSOR_QUANTITY_HUMI, /* humidity */
/* ...... */
SENSOR_QUANTITY_END,
};
```
sdev成员表示该SensorQuantity所属的SensorDevice结构其具体定义在下文给出。
最后在系统中每种物理量的SensorQuantity被分别组织成不同双链表如二氧化碳浓度SensorQuantity链表、温度SensorQuantity链表等使用的链表节点即为link成员。
## struct SensorDevice结构
```c
struct SensorDevice {
const char name[NAME_NUM_MAX]; /* name of the sensor device */
struct SensorProductInfo info; /* sensor model info, such as vendor name and model name */
struct SensorOps ops; /* filesystem-like APIs for data transferring */
struct SensorInterface interface; /* physical interface for transferring data */
struct SysDoubleLinklistNode link; /* link list node */
};
```
name成员记录传感器设备在系统中的名字用于唯一标识一个SensorDevice结构
info成员记录传感器设备的一些属性信息包括传感器的能力ability、厂家名vendor与型号product_model其中ability用一个位图表示该传感器设备可以测量的物理量
```c
#define SENSOR_ABILITY_CO2 ((uint32_t)(1 << SENSOR_QUANTITY_CO2))
#define SENSOR_ABILITY_TEMP ((uint32_t)(1 << SENSOR_QUANTITY_TEMP))
#define SENSOR_ABILITY_HUMI ((uint32_t)(1 << SENSOR_QUANTITY_HUMI))
/* ...... */
struct SensorProductInfo {
uint32_t ability; /* bitwise OR of SENSOR_ABILITY_XXX */
const char *vendor;
const char *product_model;
};
```
ops成员包含统一的、类似文件系统的API用于对传感器进行实际的数据读写。在使用一个传感器前后需要打开open/关闭close该传感器read、write分别用与从传感器接收数据与向传感器发送数据ioctl用于配置传感器属性如波特率
```c
struct SensorOps {
int (*open)(struct SensorDevice *sdev);
void (*close)(struct SensorDevice *sdev);
int (*read)(struct SensorDevice *sdev, void *buf, size_t len);
int (*write)(struct SensorDevice *sdev, const void *buf, size_t len);
int (*ioctl)(struct SensorDevice *sdev, int cmd, void *arg);
};
```
interface成员表示用于与传感器进行通信的总线设备
```c
struct SensorInterface {
device_t bus_device;
};
```
最后系统中所有注册过的传感器设备被组织成一个双链表即link成员。
## 传感器框架驱动开发
以二氧化碳传感器为例。传感器框架针对每个具体的物理量将SensorQuantity进行扩充采用类似面向对象的手段添加其他必要成员
```c
struct SensorQuantityCo2 {
struct SensorQuantity parent; /* inherit from SensorQuantity */
uint32_t (*read_concentration)(struct SensorQuantityCo2 *quant);
uint32_t last_value; /* last measured value */
uint32_t min_value; /* minimum measured value */
uint32_t max_value; /* maximum measured value */
uint32_t min_std; /* national standard: minimum */
uint32_t max_std; /* national standard: maximum */
};
```
实现SensorOps中的数据通信API具体实现细节取决于传感器型号无法实现的API可以置为NULL
```c
struct SensorOps co2_example_ops = {
.open = co2_example_open;
.close = co2_example_close;
.read = co2_example_read;
.write = NULL;
.ioctl = co2_example_ioctl;
};
```
实现SensorQuantityCo2中的read_concentration接口该接口用于读取当前空气中的二氧化碳浓度。在实现过程中可以使用SensorOps中的接口与传感器进行通信。
最后将传感器设备添加到传感器框架。分别填充SensorDevice与对应物理量的SensorQuantity结构二氧化碳即为SensorQuantityCo2)并依次使用SensorDeviceRegister和SensorQuantityRegister函数将其注册到传感器框架
```c
int SensorDeviceRegister(struct SensorDevice *sdev);
int SensorQuantityRegister(struct SensorQuantity *quant);
extern struct SensorOps co2_example_ops;
extern uint32_t co2_example_read_concentration(struct SensorQuantityCo2 *quant);
/* declare SensorDevice and SensorQuantityCo2 objects */
struct SensorDevice co2_example_sdev;
struct SensorQuantityCo2 co2_example_quant;
void register_co2_sensor()
{
/* initialize and register the SensorDevice object */
memset(&co2_example_sdev, 0, sizeof(SensorDevice));
co2_example_sdev.name = "sensor1";
co2_example_sdev.info.ability |= SENSOR_ABILITY_CO2;
co2_example_sdev.info.vendor = "xxx";
co2_example_sdev.info.product_model = "yyy";
co2_example_sdev.ops = &co2_example_ops;
co2_example_sdev.interface.bus_device = DeviceFind("uart1");
SensorDeviceRegister(&co2_example_sdev);
/* initialize and register the SensorQuantity object */
memset(&co2_example_quant, 0, sizeof(SensorQuantityCo2));
co2_example_quant.parent.name = "co2_1";
co2_example_quant.parent.type = SENSOR_QUANTITY_CO2;
co2_example_quant.parent.sdev = &co2_example_sdev;
co2_example_quant.read_concentration = co2_example_read_concentration;
SensorQuantityRegister((struct SensorQuantity *)&co2_example_quant);
}
```
## 传感器框架的使用
传感器应用开发者使用传感器框架提供的API操作传感器传感器API可以分为通用API与物理量特有API。通用API用于传感器的获取、打开与关闭物理量特有API用于传感器的数据采样。以二氧化碳传感器为例
```c
/* generic API: find a sensor quantity instance by its name */
struct SensorQuantity *SensorQuantityFind(const char *name);
/* generic API: open/close a sensor quantity instance */
int SensorQuantityOpen(struct SensorQuantity *quant);
void SensorQuantityClose(struct SensorQuantity *quant);
/* CO2 API: get current CO2 concentration reading (in ppm unit) */
uint32_t SensorCo2Read(struct SensorQuantityCo2 *quant);
```
在获取数据前,需要先获取并打开要使用的传感器;传感器打开后可以随时对传感器数据进行读取;使用完毕后,须关闭传感器。完整的使用过程示例如下:
```c
int main(int argc, char *argv[])
{
int ret;
struct SensorQuantity *quant;
struct SensorQuantityCo2 *co2_quant;
/* get the CO2 sensor quantity instance */
quant = SensorQuantityFind("co2_1");
CHECK(quant->type == SENSOR_QUANTITY_CO2);
/* open the CO2 sensor quantity instance */
co2_quant = (struct SensorQuantityCo2 *)quant;
ret = SensorQuantityOpen(quant);
CHECK(ret == EOK);
/* read CO2 concentration for 5 times, just for demonstration */
for (int i = 0; i < 5; i++)
KPrintf("Current CO2 concentration is %u ppm\n", SensorCo2Read(co2_quant));
SensorQuantityClose(quant);
return 0;
}
```

View File

@@ -0,0 +1,22 @@
config PERCEPTION_ZG09
bool "Using zg09"
default n
if PERCEPTION_ZG09
config SENSOR_DEVICE_ZG09
string "zg09 sensor name"
default "zg09_1"
config SENSOR_QUANTITY_ZG09_CO2
string "zg09 quantity name"
default "co2_1"
config SENSOR_DEVICE_ZG09_DEV
string "zg09 device name"
default "/dev/uart2_dev2"
config SENSOR_DEVICE_ZG09_DEV_EXT_PORT
int "if ZG09 device using extuart, choose port"
default "4"
endif

View File

@@ -0,0 +1,5 @@
ifeq ($(CONFIG_PERCEPTION_ZG09),y)
SRC_DIR += zg09
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,3 @@
SRC_FILES := zg09.c
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,224 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file zg09.c
* @brief ZG09 CO2 driver base perception
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021.04.22
*/
#include <sensor.h>
static uint8 zg09_set_passive[8]={0xFE, 0x06, 0x00, 0x05, 0x00, 0x00, 0x8D, 0xC4};
static uint8 zg09_set_active[8]={0xFE, 0x06, 0x00, 0x05, 0x00, 0x01, 0x4C, 0x04};
static uint8 zg09_read_instruction[8]={0xFE, 0x03, 0x00, 0x0B, 0x00, 0x01, 0xE1, 0xC7};
static struct SensorDevice zg09;
static struct SensorProductInfo info =
{
SENSOR_ABILITY_CO2,
"ZyAura",
"ZG09",
};
/**
* @description: Open ZG09 sensor device
* @param sdev - sensor device pointer
* @return success: EOK , failure: other
*/
static int SensorDeviceOpen(struct SensorDevice *sdev)
{
int result = EOK;
sdev->fd = open(SENSOR_DEVICE_ZG09_DEV, O_RDWR);
struct SerialDataCfg cfg;
cfg.serial_baud_rate = BAUD_RATE_9600;
cfg.serial_data_bits = DATA_BITS_8;
cfg.serial_stop_bits = STOP_BITS_1;
cfg.serial_buffer_size = 128;
cfg.serial_parity_mode = PARITY_NONE;
cfg.serial_bit_order = 0;
cfg.serial_invert_mode = 0;
cfg.ext_uart_no = SENSOR_DEVICE_ZG09_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
ioctl(sdev->fd, OPE_INT, &cfg);
sdev->done->ioctl(sdev, SENSOR_DEVICE_PASSIVE);
return result;
}
/**
* @description: Read sensor device
* @param sdev - sensor device pointer
* @param len - the length of the read data
* @return get data length
*/
static x_size_t SensorDeviceRead(struct SensorDevice *sdev, size_t len)
{
uint8 tmp = 0;
int timeout = 0;
while (1) {
read(sdev->fd, &tmp, 1);
if ((tmp == 0xFE) || (timeout >= 1000))
break;
UserTaskDelay(10);
++timeout;
}
if(tmp != 0xFE)
return -ERROR;
uint8 idx = 0;
sdev->buffer[idx++] = tmp;
while ((idx < len) && (timeout < 1000)) {
if (read(sdev->fd, &tmp, 1) == 1) {
timeout = 0;
sdev->buffer[idx++] = tmp;
}
++timeout;
}
return idx;
}
/**
* @description: set sensor work mode
* @param sdev - sensor device pointer
* @param cmd - mode command
* @return success: EOK , failure: -ERROR
*/
static int SensorDeviceIoctl(struct SensorDevice *sdev, int cmd)
{
switch (cmd)
{
case SENSOR_DEVICE_PASSIVE:
write(sdev->fd, zg09_set_passive, 8);
sdev->done->read(sdev, 8);
if (memcmp(sdev->buffer, zg09_set_passive, 8) == 0) {
sdev->status = SENSOR_DEVICE_PASSIVE;
return EOK;
}
break;
case SENSOR_DEVICE_ACTIVE:
write(sdev->fd, zg09_set_active, 8);
sdev->done->read(sdev, 8);
if (memcmp(sdev->buffer, zg09_set_active, 8) == 0) {
sdev->status = SENSOR_DEVICE_ACTIVE;
return EOK;
}
break;
default:
printf("This device does not have this command!\n");
break;
}
return -ERROR;
}
static struct SensorDone done =
{
SensorDeviceOpen,
NONE,
SensorDeviceRead,
NONE,
SensorDeviceIoctl,
};
/**
* @description: Init ZG09 sensor and register
* @return void
*/
static void SensorDeviceZg09Init(void)
{
zg09.name = SENSOR_DEVICE_ZG09;
zg09.info = &info;
zg09.done = &done;
SensorDeviceRegister(&zg09);
}
static struct SensorQuantity zg09_co2;
/**
* @description: Analysis ZG09 CO2 result
* @param quant - sensor quantity pointer
* @return quantity value
*/
static int32 QuantityRead(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
uint32 result;
if (quant->sdev->done->read != NONE) {
if(quant->sdev->status == SENSOR_DEVICE_PASSIVE) {
write(quant->sdev->fd, zg09_read_instruction, 8);
quant->sdev->done->read(quant->sdev, 7);
if(Crc16(quant->sdev->buffer, 5) == ((uint32)quant->sdev->buffer[6] << 8) + ((uint32)quant->sdev->buffer[5])) {
result = (uint32)quant->sdev->buffer[3] * 256 + (uint32)quant->sdev->buffer[4];
if (result > quant->value.max_value)
quant->value.max_value = result;
else if (result < quant->value.min_value)
quant->value.min_value = result;
quant->value.last_value = result;
return result;
}else{
printf("This reading is wrong\n");
result = SENSOR_QUANTITY_VALUE_ERROR;
return result;
}
}
if (quant->sdev->status == SENSOR_DEVICE_ACTIVE) {
printf("Please set passive mode.\n");
}
}else{
printf("%s don't have read done.\n", quant->name);
}
return -ERROR;
}
/**
* @description: Init ZG09 CO2 quantity and register
* @return 0
*/
int Zg09Co2Init(void)
{
SensorDeviceZg09Init();
zg09_co2.name = SENSOR_QUANTITY_ZG09_CO2;
zg09_co2.type = SENSOR_QUANTITY_CO2;
zg09_co2.value.decimal_places = 0;
zg09_co2.value.max_std = 1000;
zg09_co2.value.min_std = 350;
zg09_co2.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
zg09_co2.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
zg09_co2.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
zg09_co2.sdev = &zg09;
zg09_co2.ReadValue = QuantityRead;
SensorQuantityRegister(&zg09_co2);
return 0;
}

View File

@@ -0,0 +1,18 @@
config PERCEPTION_HS300X
bool "Using HS300x"
default n
if PERCEPTION_HS300X
config SENSOR_DEVICE_HS300X
string "HS300x sensor name"
default "hs300x_1"
config SENSOR_QUANTITY_HS300X_HUMIDITY
string "HS300x quantity name"
default "humidity_1"
config SENSOR_DEVICE_HS300X_DEV
string "HS300x device name"
default "/dev/i2c1_dev0"
endif

View File

@@ -0,0 +1,5 @@
ifeq ($(CONFIG_PERCEPTION_HS300X),y)
SRC_DIR += hs300x_humi
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,3 @@
SRC_FILES := hs300x_humi.c
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file hs300x_humi.c
* @brief HS300x humidity driver base perception
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021.04.22
*/
#include <sensor.h>
static struct SensorDevice hs300x;
static struct SensorProductInfo info =
{
(SENSOR_ABILITY_HUMI | SENSOR_ABILITY_TEMP),
"Renesas",
"HS300x",
};
/**
* @description: Open HS300x sensor device
* @param sdev - sensor device pointer
* @return EOK
*/
static int SensorDeviceOpen(struct SensorDevice *sdev)
{
sdev->fd = open(SENSOR_DEVICE_HS300X_DEV, O_RDWR);
return EOK;
}
/**
* @description: Read sensor device
* @param sdev - sensor device pointer
* @param len - the length of the read data
* @return success: EOK , failure: -ERROR
*/
static x_size_t SensorDeviceRead(struct SensorDevice *sdev, size_t len)
{
if (write(sdev->fd, NONE, 0) != 1)
return -ERROR;
UserTaskDelay(50);
if (read(sdev->fd, sdev->buffer, len) != 1)
return -ERROR;
return EOK;
}
static struct SensorDone done =
{
SensorDeviceOpen,
NONE,
SensorDeviceRead,
NONE,
NONE,
};
/**
* @description: Init HS300x sensor and register
* @return void
*/
static void SensorDeviceHs300xInit(void)
{
hs300x.name = SENSOR_DEVICE_HS300X;
hs300x.info = &info;
hs300x.done = &done;
hs300x.status = SENSOR_DEVICE_PASSIVE;
SensorDeviceRegister(&hs300x);
}
static struct SensorQuantity hs300x_humidity;
/**
* @description: Analysis HS300x humidity result
* @param quant - sensor quantity pointer
* @return quantity value
*/
static int32 ReadHumidity(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
float result = 0.0;
if (quant->sdev->done->read != NONE) {
if (quant->sdev->status == SENSOR_DEVICE_PASSIVE) {
quant->sdev->done->read(quant->sdev, 4);
quant->sdev->done->read(quant->sdev, 4); /* It takes two reads to get the data right */
result = ((quant->sdev->buffer[0] << 8 | quant->sdev->buffer[1] ) & 0x3fff) * 100.0 / ( (1 << 14) - 1);
return (int32)(result * 10);
}
if (quant->sdev->status == SENSOR_DEVICE_ACTIVE) {
printf("Please set passive mode.\n");
}
}else{
printf("%s don't have read done.\n", quant->name);
}
return -ERROR;
}
/**
* @description: Init HS300x humidity quantity and register
* @return 0
*/
int Hs300xHumidityInit(void)
{
SensorDeviceHs300xInit();
hs300x_humidity.name = SENSOR_QUANTITY_HS300X_HUMIDITY;
hs300x_humidity.type = SENSOR_QUANTITY_HUMI;
hs300x_humidity.value.decimal_places = 1;
hs300x_humidity.value.max_std = 1000;
hs300x_humidity.value.min_std = 0;
hs300x_humidity.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
hs300x_humidity.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
hs300x_humidity.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
hs300x_humidity.sdev = &hs300x;
hs300x_humidity.ReadValue = ReadHumidity;
SensorQuantityRegister(&hs300x_humidity);
return 0;
}

View File

@@ -0,0 +1,30 @@
config PERCEPTION_PS5308
bool "Using PS5308"
default n
if PERCEPTION_PS5308
config SENSOR_DEVICE_PS5308
string "PS5308 sensor name"
default "ps5308_1"
config SENSOR_QUANTITY_PS5308_PM1_0
string "PS5308 quantity PM1.0 name"
default "pm1_0_1"
config SENSOR_QUANTITY_PS5308_PM2_5
string "PS5308 quantity PM2.5 name"
default "pm2_5_1"
config SENSOR_QUANTITY_PS5308_PM10
string "PS5308 quantity PM10 name"
default "pm10_1"
config SENSOR_DEVICE_PS5308_DEV
string "PS5308 device name"
default "/dev/uart2_dev2"
config SENSOR_DEVICE_PS5308_DEV_EXT_PORT
int "if PS5308 device using extuart, choose port"
default "4"
endif

View File

@@ -0,0 +1,5 @@
ifeq ($(CONFIG_PERCEPTION_PS5308),y)
SRC_DIR += ps5308
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,3 @@
SRC_FILES := ps5308.c
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,359 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file ps5308.c
* @brief PS5308 PM1.0, PM2.5, PM10, driver base perception
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021.04.22
*/
#include <sensor.h>
static struct SensorDevice ps5308;
static int32_t active_task_id;
static int buff_lock;
static struct SensorProductInfo info =
{
SENSOR_ABILITY_PM,
"Pulsensor",
"PS5308",
};
/**
* @description: Read sensor task
* @param sdev - sensor device pointer
*/
static void ReadTask(struct SensorDevice *sdev)
{
while (1) {
UserMutexObtain(buff_lock, WAITING_FOREVER);
sdev->done->read(sdev, 32);
UserMutexAbandon(buff_lock);
UserTaskDelay(750);
}
}
/**
* @description: Open PS5308 sensor device
* @param sdev - sensor device pointer
* @return success: EOK , failure: other
*/
static int SensorDeviceOpen(struct SensorDevice *sdev)
{
int result = EOK;
buff_lock = UserMutexCreate();
sdev->fd = open(SENSOR_DEVICE_PS5308_DEV, O_RDWR);
struct SerialDataCfg cfg;
cfg.serial_baud_rate = BAUD_RATE_9600;
cfg.serial_data_bits = DATA_BITS_8;
cfg.serial_stop_bits = STOP_BITS_1;
cfg.serial_buffer_size = 128;
cfg.serial_parity_mode = PARITY_NONE;
cfg.serial_bit_order = 0;
cfg.serial_invert_mode = 0;
cfg.ext_uart_no = SENSOR_DEVICE_PS5308_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
result = ioctl(sdev->fd, OPE_INT, &cfg);
utask_x active_task;
const char name[NAME_NUM_MAX] = "ps5308_task";
strncpy(active_task.name, name, strlen(name));
active_task.func_entry = ReadTask;
active_task.func_param = sdev;
active_task.prio = KTASK_PRIORITY_MAX/2;
active_task.stack_size = 1024;
active_task_id = UserTaskCreate(active_task);
result = UserTaskStartup(active_task_id);
return result;
}
/**
* @description: Close PS5308 sensor device
* @param sdev - sensor device pointer
* @return EOK
*/
static int SensorDeviceClose(struct SensorDevice *sdev)
{
UserTaskDelete(active_task_id);
UserMutexDelete(buff_lock);
return EOK;
}
/**
* @description: Read sensor device
* @param sdev - sensor device pointer
* @param len - the length of the read data
* @return get data length
*/
static x_size_t SensorDeviceRead(struct SensorDevice *sdev, size_t len)
{
uint8 tmp = 0;
int timeout = 0;
while (1) {
read(sdev->fd, &tmp, 1);
if ((tmp == 0x44) || (timeout >= 1000))
break;
UserTaskDelay(10);
++timeout;
}
if (tmp != 0x44)
return -ERROR;
uint8 idx = 0;
sdev->buffer[idx++] = tmp;
while ((idx < len) && (timeout < 1000)) {
if (read(sdev->fd, &tmp, 1) == 1) {
timeout = 0;
sdev->buffer[idx++] = tmp;
}
++timeout;
}
return idx;
}
static struct SensorDone SensorDeviceDone =
{
SensorDeviceOpen,
SensorDeviceClose,
SensorDeviceRead,
NONE,
NONE,
};
/**
* @description: Init PS5308 sensor and register
* @return void
*/
static void Ps5308Init(void)
{
ps5308.name = SENSOR_DEVICE_PS5308;
ps5308.info = &info;
ps5308.done = &SensorDeviceDone;
ps5308.status = SENSOR_DEVICE_ACTIVE;
SensorDeviceRegister(&ps5308);
}
#ifdef SENSOR_QUANTITY_PS5308_PM1_0
static struct SensorQuantity ps5308_pm1_0;
/**
* @description: Analysis PS5308 PM1.0 result
* @param quant - sensor quantity pointer
* @return quantity value
*/
static int32 ReadPm1_0(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
uint32 result;
if (quant->sdev->done->read != NONE) {
uint16 checksum = 0;
UserMutexObtain(buff_lock, WAITING_FOREVER);
for (uint8 i = 0; i < 30; i++)
checksum += quant->sdev->buffer[i];
if (checksum == (((uint16)quant->sdev->buffer[30] << 8) + ((uint16)quant->sdev->buffer[31]))) {
result = ((uint16)quant->sdev->buffer[4] << 8) + (uint16)quant->sdev->buffer[5];
if (result > quant->value.max_value)
quant->value.max_value = result;
else if (result < quant->value.min_value)
quant->value.min_value = result;
quant->value.last_value = result;
return result;
}else{
printf("This reading is wrong\n");
result = SENSOR_QUANTITY_VALUE_ERROR;
return result;
}
}else{
printf("%s don't have read done.\n", quant->name);
}
return -ERROR;
}
/**
* @description: Init PS5308 PM1.0 quantity and register
* @return 0
*/
int Ps5308Pm1_0Init(void)
{
Ps5308Init();
ps5308_pm1_0.name = SENSOR_QUANTITY_PS5308_PM1_0;
ps5308_pm1_0.type = SENSOR_QUANTITY_PM;
ps5308_pm1_0.value.decimal_places = 0;
ps5308_pm1_0.value.max_std = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm1_0.value.min_std = 0;
ps5308_pm1_0.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm1_0.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm1_0.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm1_0.sdev = &ps5308;
ps5308_pm1_0.ReadValue = ReadPm1_0;
SensorQuantityRegister(&ps5308_pm1_0);
return 0;
}
#endif
#ifdef SENSOR_QUANTITY_PS5308_PM2_5
static struct SensorQuantity ps5308_pm2_5;
/**
* @description: Analysis PS5308 PM2.5 result
* @param quant - sensor quantity pointer
* @return quantity value
*/
static int32 ReadPm2_5(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
uint32 result;
if (quant->sdev->done->read != NONE) {
uint16 checksum = 0;
UserMutexObtain(buff_lock, WAITING_FOREVER);
for (uint i = 0; i < 30; i++)
checksum += quant->sdev->buffer[i];
if (checksum == (((uint16)quant->sdev->buffer[30] << 8) + ((uint16)quant->sdev->buffer[31]))) {
result = ((uint16)quant->sdev->buffer[6] << 8) + (uint16)quant->sdev->buffer[7];
if (result > quant->value.max_value)
quant->value.max_value = result;
else if (result < quant->value.min_value)
quant->value.min_value = result;
quant->value.last_value = result;
return result;
}else{
printf("This reading is wrong\n");
result = SENSOR_QUANTITY_VALUE_ERROR;
return result;
}
}else{
printf("%s don't have read done.\n", quant->name);
}
return -ERROR;
}
/**
* @description: Init PS5308 PM2.5 quantity and register
* @return 0
*/
int Ps5308Pm2_5Init(void)
{
Ps5308Init();
ps5308_pm2_5.name = SENSOR_QUANTITY_PS5308_PM2_5;
ps5308_pm2_5.type = SENSOR_QUANTITY_PM;
ps5308_pm2_5.value.decimal_places = 0;
ps5308_pm2_5.value.max_std = 35;
ps5308_pm2_5.value.min_std = 0;
ps5308_pm2_5.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm2_5.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm2_5.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm2_5.sdev = &ps5308;
ps5308_pm2_5.ReadValue = ReadPm2_5;
SensorQuantityRegister(&ps5308_pm2_5);
return 0;
}
#endif
#ifdef SENSOR_QUANTITY_PS5308_PM10
static struct SensorQuantity ps5308_pm10;
/**
* @description: Analysis PS5308 PM10 result
* @param quant - sensor quantity pointer
* @return quantity value
*/
static int32 ReadPm10(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
uint32 result;
if (quant->sdev->done->read != NONE) {
uint16 checksum = 0;
UserMutexObtain(buff_lock, WAITING_FOREVER);
for (uint i = 0; i < 30; i++)
checksum += quant->sdev->buffer[i];
if (checksum == (((uint16)quant->sdev->buffer[30] << 8) + ((uint16)quant->sdev->buffer[31]))) {
result = ((uint16)quant->sdev->buffer[8] << 8) + (uint16)quant->sdev->buffer[9];
if (result > quant->value.max_value)
quant->value.max_value = result;
else if (result < quant->value.min_value)
quant->value.min_value = result;
quant->value.last_value = result;
return result;
}else{
printf("This reading is wrong\n");
result = SENSOR_QUANTITY_VALUE_ERROR;
return result;
}
}else{
printf("%s don't have read done.\n", quant->name);
}
return -ERROR;
}
/**
* @description: Init PS5308 PM10 quantity and register
* @return 0
*/
int Ps5308Pm10Init(void)
{
Ps5308Init();
ps5308_pm10.name = SENSOR_QUANTITY_PS5308_PM10;
ps5308_pm10.type = SENSOR_QUANTITY_PM;
ps5308_pm10.value.decimal_places = 0;
ps5308_pm10.value.max_std = 75;
ps5308_pm10.value.min_std = 0;
ps5308_pm10.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm10.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm10.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
ps5308_pm10.sdev = &ps5308;
ps5308_pm10.ReadValue = ReadPm10;
SensorQuantityRegister(&ps5308_pm10);
return 0;
}
#endif

View File

@@ -0,0 +1,393 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file sensor.c
* @brief Implement the sensor framework management, registration and done
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021.03.24
*/
#include <sensor.h>
/* Sensor quantity list table */
static DoubleLinklistType quant_table[SENSOR_QUANTITY_END];
/* Sensor device list */
static DoubleLinklistType sensor_device_list;
/* Sensor quantity list lock */
static int quant_table_lock;
/* Sensor device list lock */
static int sensor_device_list_lock;
/**
* @description: Init perception framework
* @return 0
*/
int SensorFrameworkInit(void)
{
for (int i = 0; i < SENSOR_QUANTITY_END; i++)
InitDoubleLinkList(&quant_table[i]);
InitDoubleLinkList(&sensor_device_list);
quant_table_lock = UserMutexCreate();
sensor_device_list_lock = UserMutexCreate();
return 0;
}
/* ============================= Sensor device interface operations ============================= */
/**
* @description: Find sensor device by name
* @param name - name string
* @return sensor device pointer
*/
static struct SensorDevice *SensorDeviceFindByName(const char *name)
{
struct SensorDevice *ret = NONE;
struct SysDoubleLinklistNode *node;
if (name == NONE)
return NONE;
UserMutexObtain(sensor_device_list_lock, WAITING_FOREVER);
DOUBLE_LINKLIST_FOR_EACH(node, &sensor_device_list) {
struct SensorDevice *sdev =CONTAINER_OF(node,
struct SensorDevice, link);
if (strncmp(sdev->name, name, NAME_NUM_MAX) == 0) {
ret = sdev;
break;
}
}
UserMutexAbandon(sensor_device_list_lock);
return ret;
}
/**
* @description: Check whether the sensor is capable
* @param sdev - sensor device pointer
* @param ability - the ability to detect certain data
* @return success: true , failure: false
*/
inline int SensorDeviceCheckAbility(struct SensorDevice *sdev, uint32_t ability)
{
return (sdev->info->ability & ability) != 0;
}
/**
* @description: Register the sensor to the linked list
* @param sdev - sensor device pointer
* @return success: EOK , failure: -ERROR
*/
int SensorDeviceRegister(struct SensorDevice *sdev)
{
if (sdev == NONE)
return -ERROR;
if (SensorDeviceFindByName(sdev->name) != NONE) {
printf("%s: sensor with the same name already registered\n", __func__);
return -ERROR;
}
sdev->ref_cnt = 0;
InitDoubleLinkList(&sdev->quant_list);
UserMutexObtain(sensor_device_list_lock, WAITING_FOREVER);
DoubleLinkListInsertNodeAfter(&sensor_device_list, &sdev->link);
UserMutexAbandon(sensor_device_list_lock);
return EOK;
}
/**
* @description: Unregister the sensor from the linked list
* @param sdev - sensor device pointer
* @return EOK
*/
int SensorDeviceUnregister(struct SensorDevice *sdev)
{
if (!sdev)
return -ERROR;
UserMutexObtain(sensor_device_list_lock, WAITING_FOREVER);
DoubleLinkListRmNode(&sdev->link);
UserMutexAbandon(sensor_device_list_lock);
return EOK;
}
/**
* @description: Open sensor device
* @param sdev - sensor device pointer
* @return success: EOK , failure: other
*/
static int SensorDeviceOpen(struct SensorDevice *sdev)
{
if (!sdev)
return -ERROR;
int result = EOK;
if (sdev->done->open != NONE)
result = sdev->done->open(sdev);
if (result == EOK) {
printf("Device %s open success.\n", sdev->name);
}else{
if (sdev->fd)
close(sdev->fd);
printf("Device %s open failed(%d).\n", sdev->name, result);
memset(sdev, 0, sizeof(struct SensorDevice));
}
return result;
}
/**
* @description: Close sensor device
* @param sdev - sensor device pointer
* @return success: EOK , failure: other
*/
static int SensorDeviceClose(struct SensorDevice *sdev)
{
int result = EOK;
if (sdev->fd)
close(sdev->fd);
if (sdev->done->close != NONE)
result = sdev->done->close(sdev);
if (result == EOK)
printf("%s successfully closed.\n", sdev->name);
else
printf("Closed %s failure.\n", sdev->name);
return result;
}
/* ============================= Sensor quantity interface operations ============================= */
/**
* @description: Find sensor quantity by name
* @param name - name string
* @param type - the quantity required
* @return sensor quantity pointer
*/
struct SensorQuantity *SensorQuantityFind(const char *name,
enum SensorQuantityType type)
{
struct SensorQuantity *ret = NONE;
struct SysDoubleLinklistNode *node;
if (name == NONE || type < 0 || type >= SENSOR_QUANTITY_END)
return NONE;
UserMutexObtain(quant_table_lock, WAITING_FOREVER);
DOUBLE_LINKLIST_FOR_EACH(node, &quant_table[type]) {
struct SensorQuantity *quant =CONTAINER_OF(node,
struct SensorQuantity, link);
if (strncmp(quant->name, name, NAME_NUM_MAX) == 0) {
ret = quant;
break;
}
}
UserMutexAbandon(quant_table_lock);
return ret;
}
/**
* @description: Register the quantity to the linked list
* @param quant - sensor quantity pointer
* @return success: EOK , failure: -ERROR
*/
int SensorQuantityRegister(struct SensorQuantity *quant)
{
if (quant == NONE)
return -ERROR;
if (SensorDeviceFindByName(quant->sdev->name) == NONE) {
if(SensorDeviceRegister(quant->sdev) != EOK)
return -ERROR;
}
UserMutexObtain(quant_table_lock, WAITING_FOREVER);
DoubleLinkListInsertNodeAfter(&quant->sdev->quant_list, &quant->quant_link);
DoubleLinkListInsertNodeAfter(&quant_table[quant->type], &quant->link);
UserMutexAbandon(quant_table_lock);
return EOK;
}
/**
* @description: Unregister the quantity from the linked list
* @param quant - sensor quantity pointer
* @return EOK
*/
int SensorQuantityUnregister(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
UserMutexObtain(quant_table_lock, WAITING_FOREVER);
DoubleLinkListRmNode(&quant->quant_link);
DoubleLinkListRmNode(&quant->link);
UserMutexAbandon(quant_table_lock);
return EOK;
}
/**
* @description: Open the sensor quantity
* @param quant - sensor quantity pointer
* @return success: EOK , failure: other
*/
int SensorQuantityOpen(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
int ret = EOK;
struct SensorDevice *sdev = quant->sdev;
if (!sdev)
return -ERROR;
if (sdev->ref_cnt == 0) {
ret = SensorDeviceOpen(sdev);
if (ret != EOK) {
printf("%s: open sensor device failed\n", __func__);
return ret;
}
}
sdev->ref_cnt++;
return ret;
}
/**
* @description: Close sensor quantity
* @param quant - sensor quantity pointer
* @return success: EOK , failure: other
*/
int SensorQuantityClose(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
int ret = EOK;
struct SensorDevice *sdev = quant->sdev;
if (!sdev)
return -ERROR;
if (sdev->ref_cnt == 0)
return ret;
sdev->ref_cnt--;
if (sdev->ref_cnt == 0)
ret = SensorDeviceClose(sdev);
return ret;
}
/**
* @description: Read quantity current value
* @param quant - sensor quantity pointer
* @return quantity value
*/
int32 SensorQuantityRead(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
int32 result = 0;
struct SensorDevice *sdev = quant->sdev;
if (!sdev)
return -ERROR;
if (quant->ReadValue != NONE) {
result = quant->ReadValue(quant);
}
return result;
}
/**
* @description: Configure quantity mode
* @param quant - sensor quantity pointer
* @param cmd - mode command
* @return success: EOK , failure: other
*/
int SensorQuantityControl(struct SensorQuantity *quant, int cmd)
{
if (!quant)
return -ERROR;
if (quant->sdev->done->ioctl != NONE) {
return quant->sdev->done->ioctl(quant->sdev, cmd);
}
return -ENONESYS;
}
/* ============================= Check function ============================= */
/**
* @description: CRC16 check
* @param data sensor receive buffer
* @param length sensor receive buffer minus check code
* @return check code
*/
uint32 Crc16(uint8 * data, uint8 length)
{
int j;
unsigned int reg_crc=0xFFFF;
while (length--) {
reg_crc ^= *data++;
for (j=0;j<8;j++) {
if(reg_crc & 0x01)
reg_crc=reg_crc >>1 ^ 0xA001;
else
reg_crc=reg_crc >>1;
}
}
return reg_crc;
}
/**
* @description: The checksum
* @param data sensor receive buffer
* @param head not check head length
* @param length sensor receive buffer minus check code
* @return check code
*/
uint8 GetCheckSum(uint8 *data, uint8 head, uint8 length)
{
uint8 i;
uint8 checksum = 0;
for (i = head; i < length; i++) {
checksum += data[i];
}
checksum = ~checksum + 1;
return checksum;
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file sensor.h
* @brief Structure and function declarations of the sensor framework
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021.03.24
*/
#ifndef SENSOR_H
#define SENSOR_H
#include <bus.h>
#include <bus_serial.h>
#include <dev_serial.h>
#include <string.h>
#include <user_api.h>
#define SENSOR_QUANTITY_VALUE_ERROR ((uint32)0xffffffff)
/* Sensor quantity report mode */
#define SENSOR_DEVICE_PASSIVE 0x00
#define SENSOR_DEVICE_ACTIVE 0x01
#define SENSOR_RECEIVE_BUFFSIZE 32
#if SENSOR_TYPE_END > 32
#error "Too many sensor types"
#endif
/* Sensor ability */
#define SENSOR_ABILITY_CO2 ((uint32_t)(1 << SENSOR_QUANTITY_CO2))
#define SENSOR_ABILITY_TEMP ((uint32_t)(1 << SENSOR_QUANTITY_TEMP))
#define SENSOR_ABILITY_HUMI ((uint32_t)(1 << SENSOR_QUANTITY_HUMI))
#define SENSOR_ABILITY_HCHO ((uint32_t)(1 << SENSOR_QUANTITY_HCHO))
#define SENSOR_ABILITY_CO ((uint32_t)(1 << SENSOR_QUANTITY_CO))
#define SENSOR_ABILITY_PM ((uint32_t)(1 << SENSOR_QUANTITY_PM))
#define SENSOR_ABILITY_VOICE ((uint32_t)(1 << SENSOR_QUANTITY_VOICE))
struct SensorProductInfo {
uint32_t ability; /* sensor ability */
const char *vendor_name;
const char *model_name;
};
struct SensorDevice;
struct SensorDone {
int (*open)(struct SensorDevice *sdev);
int (*close)(struct SensorDevice *sdev);
x_size_t (*read)(struct SensorDevice *sdev, size_t len);
int (*write)(struct SensorDevice *sdev, const void *buf, size_t len);
int (*ioctl)(struct SensorDevice *sdev, int cmd);
};
struct SensorDevice {
char *name;
struct SensorProductInfo *info;
struct SensorDone *done;
int fd;
int status;
uint8 buffer[SENSOR_RECEIVE_BUFFSIZE];
int ref_cnt;
DoubleLinklistType quant_list;
struct SysDoubleLinklistNode link;
};
enum SensorQuantityType {
SENSOR_QUANTITY_CO2 = 0,
SENSOR_QUANTITY_TEMP,
SENSOR_QUANTITY_HUMI,
SENSOR_QUANTITY_HCHO,
SENSOR_QUANTITY_CO,
SENSOR_QUANTITY_PM,
SENSOR_QUANTITY_VOICE,
SENSOR_QUANTITY_END,
};
struct SensorQuantityValue {
uint8 decimal_places; /* The decimal place of the result */
uint32 last_value; /* The last read value, if it does not exist, is SENSOR_QUANTITY_VALUE_ERROR */
uint32 min_value; /* The minimum read value, if it does not exist, is SENSOR_QUANTITY_VALUE_ERROR */
uint32 max_value; /* The maximum read value, if it does not exist, is SENSOR_QUANTITY_VALUE_ERROR */
uint32 min_std; /* The minimum standard value, if it does not exist, is SENSOR_QUANTITY_VALUE_ERROR */
uint32 max_std; /* The maximum standard value, if it does not exist, is SENSOR_QUANTITY_VALUE_ERROR */
};
struct SensorQuantity {
char *name;
enum SensorQuantityType type;
struct SensorQuantityValue value;
struct SensorDevice *sdev;
int32 (*ReadValue)(struct SensorQuantity *quant);
struct SysDoubleLinklistNode quant_link;
struct SysDoubleLinklistNode link;
};
int SensorDeviceRegister(struct SensorDevice *sdev);
int SensorDeviceUnregister(struct SensorDevice *sdev);
struct SensorQuantity *SensorQuantityFind(const char *name, enum SensorQuantityType type);
int SensorQuantityRegister(struct SensorQuantity *quant);
int SensorQuantityUnregister(struct SensorQuantity *quant);
int SensorQuantityOpen(struct SensorQuantity *quant);
int SensorQuantityClose(struct SensorQuantity *quant);
int32 SensorQuantityRead(struct SensorQuantity *quant);
int SensorQuantityControl(struct SensorQuantity *quant, int cmd);
uint32 Crc16(uint8 * data, uint8 length);
uint8 GetCheckSum(uint8 *data, uint8 head, uint8 length);
#endif

View File

@@ -0,0 +1,18 @@
config PERCEPTION_HS300X
bool "Using HS300x"
default n
if PERCEPTION_HS300X
config SENSOR_DEVICE_HS300X
string "HS300x sensor name"
default "hs300x_1"
config SENSOR_QUANTITY_HS300X_TEMPERATURE
string "HS300x quantity name"
default "temperature_1"
config SENSOR_DEVICE_HS300X_DEV
string "HS300x device name"
default "/dev/i2c1_dev0"
endif

View File

@@ -0,0 +1,5 @@
ifeq ($(CONFIG_PERCEPTION_HS300X),y)
SRC_DIR += hs300x_temp
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,3 @@
SRC_FILES := hs300x_temp.c
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file hs300x_temp.c
* @brief HS300x temperature driver base perception
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021.04.22
*/
#include <sensor.h>
static struct SensorDevice hs300x;
static struct SensorProductInfo info =
{
(SENSOR_ABILITY_HUMI | SENSOR_ABILITY_TEMP),
"Renesas",
"HS300x",
};
/**
* @description: Open HS300x sensor device
* @param sdev - sensor device pointer
* @return EOK
*/
static int SensorDeviceOpen(struct SensorDevice *sdev)
{
sdev->fd = open(SENSOR_DEVICE_HS300X_DEV, O_RDWR);
return EOK;
}
/**
* @description: Read sensor device
* @param sdev - sensor device pointer
* @param len - the length of the read data
* @return success: EOK , failure: -ERROR
*/
static x_size_t SensorDeviceRead(struct SensorDevice *sdev, size_t len)
{
if (write(sdev->fd, NONE, 0) != 1)
return -ERROR;
UserTaskDelay(50);
if (read(sdev->fd, sdev->buffer, len) != 1)
return -ERROR;
return EOK;
}
static struct SensorDone done =
{
SensorDeviceOpen,
NONE,
SensorDeviceRead,
NONE,
NONE,
};
/**
* @description: Init HS300x sensor and register
* @return void
*/
static void SensorDeviceHs300xInit(void)
{
hs300x.name = SENSOR_DEVICE_HS300X;
hs300x.info = &info;
hs300x.done = &done;
hs300x.status = SENSOR_DEVICE_PASSIVE;
SensorDeviceRegister(&hs300x);
}
static struct SensorQuantity hs300x_temperature;
/**
* @description: Analysis HS300x temperature result
* @param quant - sensor quantity pointer
* @return quantity value
*/
static int32 ReadTemperature(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
float result;
if (quant->sdev->done->read != NONE) {
if (quant->sdev->status == SENSOR_DEVICE_PASSIVE) {
quant->sdev->done->read(quant->sdev, 4);
quant->sdev->done->read(quant->sdev, 4); /* It takes two reads to get the data right */
result = ((quant->sdev->buffer[2] << 8 | quant->sdev->buffer[3]) >> 2) * 165.0 /( (1 << 14) - 1) - 40.0;
return (int32)(result * 10);
}
if (quant->sdev->status == SENSOR_DEVICE_ACTIVE) {
printf("Please set passive mode.\n");
}
}else{
printf("%s don't have read done.\n", quant->name);
}
return -ERROR;
}
/**
* @description: Init HS300x temperature quantity and register
* @return 0
*/
int Hs300xTemperatureInit(void)
{
SensorDeviceHs300xInit();
hs300x_temperature.name = SENSOR_QUANTITY_HS300X_TEMPERATURE;
hs300x_temperature.type = SENSOR_QUANTITY_TEMP;
hs300x_temperature.value.decimal_places = 1;
hs300x_temperature.value.max_std = 1000;
hs300x_temperature.value.min_std = 0;
hs300x_temperature.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
hs300x_temperature.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
hs300x_temperature.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
hs300x_temperature.sdev = &hs300x;
hs300x_temperature.ReadValue = ReadTemperature;
SensorQuantityRegister(&hs300x_temperature);
return 0;
}

View File

@@ -0,0 +1,22 @@
config PERCEPTION_D124
bool "Using D124"
default n
if PERCEPTION_D124
config SENSOR_DEVICE_D124
string "D124 sensor name"
default "d124_1"
config SENSOR_QUANTITY_D124_VOICE
string "D124 quantity PM1.0 name"
default "voice_1"
config SENSOR_DEVICE_D124_DEV
string "D124 device name"
default "/dev/extuart_dev4"
config SENSOR_DEVICE_D124_DEV_EXT_PORT
int "if D124 device using extuart, choose port"
default "4"
endif

View File

@@ -0,0 +1,5 @@
ifeq ($(CONFIG_PERCEPTION_D124),y)
SRC_DIR += d124
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,3 @@
SRC_FILES := d124.c
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -0,0 +1,219 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file d124.c
* @brief D124 voice driver base perception
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021.04.22
*/
#include <sensor.h>
static struct SensorDevice d124;
static int32_t active_task_id;
static int buff_lock;
static struct SensorProductInfo info =
{
SENSOR_ABILITY_VOICE,
"龙戈电子",
"D124",
};
/**
* @description: Read sensor task
* @param sdev - sensor device pointer
*/
static void ReadTask(struct SensorDevice *sdev)
{
while (1) {
UserMutexObtain(buff_lock, WAITING_FOREVER);
sdev->done->read(sdev, 5);
UserMutexAbandon(buff_lock);
UserTaskDelay(750);
}
}
/**
* @description: Open D124 voice device
* @param sdev - sensor device pointer
* @return success: EOK , failure: other
*/
static int SensorDeviceOpen(struct SensorDevice *sdev)
{
int result = EOK;
buff_lock = UserMutexCreate();
sdev->fd = open(SENSOR_DEVICE_D124_DEV, O_RDWR);
struct SerialDataCfg cfg;
cfg.serial_baud_rate = BAUD_RATE_9600;
cfg.serial_data_bits = DATA_BITS_8;
cfg.serial_stop_bits = STOP_BITS_1;
cfg.serial_buffer_size = 64;
cfg.serial_parity_mode = PARITY_NONE;
cfg.serial_bit_order = 0;
cfg.serial_invert_mode = 0;
cfg.ext_uart_no = SENSOR_DEVICE_D124_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
result = ioctl(sdev->fd, OPE_INT, &cfg);
utask_x active_task;
const char name[NAME_NUM_MAX] = "d124_task";
strncpy(active_task.name, name, strlen(name));
active_task.func_entry = ReadTask;
active_task.func_param = sdev;
active_task.prio = KTASK_PRIORITY_MAX/2;
active_task.stack_size = 2048;
active_task_id = UserTaskCreate(active_task);
result = UserTaskStartup(active_task_id);
return result;
}
/**
* @description: Close D124 sensor device
* @param sdev - sensor device pointer
* @return EOK
*/
static int SensorDeviceClose(struct SensorDevice *sdev)
{
UserTaskDelete(active_task_id);
UserMutexDelete(buff_lock);
return EOK;
}
/**
* @description: Read sensor device
* @param sdev - sensor device pointer
* @param len - the length of the read data
* @return get data length
*/
static x_size_t SensorDeviceRead(struct SensorDevice *sdev, size_t len)
{
uint8 tmp = 0;
int timeout = 0;
while (1) {
read(sdev->fd, &tmp, 1);
if ((tmp == 0xAA) || (timeout >= 1000))
break;
UserTaskDelay(10);
++timeout;
}
if(tmp != 0xAA)
return -ERROR;
uint8 idx = 0;
sdev->buffer[idx++] = tmp;
while ((idx < len) && (timeout < 1000)) {
if (read(sdev->fd, &tmp, 1) == 1) {
timeout = 0;
sdev->buffer[idx++] = tmp;
}
++timeout;
}
return idx;
}
static struct SensorDone done =
{
SensorDeviceOpen,
SensorDeviceClose,
SensorDeviceRead,
NONE,
NONE,
};
/**
* @description: Init D124 sensor and register
* @return void
*/
static void D124Init(void)
{
d124.name = SENSOR_DEVICE_D124;
d124.info = &info;
d124.done = &done;
d124.status = SENSOR_DEVICE_ACTIVE;
SensorDeviceRegister(&d124);
}
static struct SensorQuantity d124_voice;
/**
* @description: Analysis D124 voice result
* @param quant - sensor quantity pointer
* @return quantity value
*/
static int32 ReadVoice(struct SensorQuantity *quant)
{
if (!quant)
return -ERROR;
uint32 result;
if (quant->sdev->done->read != NONE) {
UserMutexObtain(buff_lock, WAITING_FOREVER);
if (quant->sdev->buffer[3] == quant->sdev->buffer[1] + quant->sdev->buffer[2]) {
result = ((uint16)quant->sdev->buffer[1] << 8) + (uint16)quant->sdev->buffer[2];
if (result > quant->value.max_value)
quant->value.max_value = result;
else if (result < quant->value.min_value)
quant->value.min_value = result;
quant->value.last_value = result;
return result;
}else{
printf("This reading is wrong\n");
result = SENSOR_QUANTITY_VALUE_ERROR;
return result;
}
}else{
printf("%s don't have read done.\n", quant->name);
}
return -ERROR;
}
/**
* @description: Init D124 voice quantity and register
* @return 0
*/
int D124VoiceInit(void)
{
D124Init();
d124_voice.name = SENSOR_QUANTITY_D124_VOICE;
d124_voice.type = SENSOR_QUANTITY_VOICE;
d124_voice.value.decimal_places = 1;
d124_voice.value.max_std = 600;
d124_voice.value.min_std = 0;
d124_voice.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
d124_voice.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
d124_voice.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
d124_voice.sdev = &d124;
d124_voice.ReadValue = ReadVoice;
SensorQuantityRegister(&d124_voice);
return 0;
}