192 lines
17 KiB
HTML
192 lines
17 KiB
HTML
<!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 << SENSOR_QUANTITY_CO2))</span>
|
||
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> SENSOR_ABILITY_TEMP ((uint32_t)(1 << SENSOR_QUANTITY_TEMP))</span>
|
||
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> SENSOR_ABILITY_HUMI ((uint32_t)(1 << 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>(&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 = &co2_example_ops;
|
||
co2_example_sdev.interface.bus_device = DeviceFind(<span class="hljs-string">"uart1"</span>);
|
||
|
||
SensorDeviceRegister(&co2_example_sdev);
|
||
|
||
|
||
<span class="hljs-comment">/* initialize and register the SensorQuantity object */</span>
|
||
<span class="hljs-built_in">memset</span>(&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 = &co2_example_sdev;
|
||
co2_example_quant.read_concentration = co2_example_read_concentration;
|
||
|
||
SensorQuantityRegister((struct SensorQuantity *)&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->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 < <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> |