开发设备驱动程序
内置于 Wolfram 语言中的 Wolfram Device Framework(Wolfram 设备框架)创建了代表外部设备的符号对象,简化与设备间的交互,使得编写设备驱动程序变得容易. “框架”中的设备可以表示一个实际的设备,诸如,温度感应器,或封装一个端口,例如串行端口. 该教程为设备驱动程序的的高级用户和开发人员解释了“框架”的内部原理. 用户级别的与设备交互的详情,请参阅“使用连接设备”.
对于大多数设备,组成“框架”的函数并不直接关注设备编程或底层硬件通讯软件. 基于硬件设备的不同,这种实现也会不一样. 例如,它可能会包含用 C 编写底层设备程序(或由第三方提供),然后使用 WSTP API 把这些程序的接口连接到程序包级别的 Wolfram 语言函数. 这些函数会由“框架”以合适的方式串起来,创建 Wolfram 语言设备驱动程序. 另一种实现方法是可能完全避免底层的 C 编程,使用 Wolfram 语言的 .NET/Link 功能,从 Wolfram 语言函数内部的驱动程序级别与设备交互. “框架”的职能就是整合这些函数,通过用户级函数的集合,提供与设备接口的统一方法.
DeviceFramework`DeviceClassRegister["class",opts] | |
对指定的类注册设备驱动程序,它的操作由选项 opts 定义 | |
DeviceFramework`DeviceClassRegister["class","parent",opts] | |
注册与 parent 相同的类,除了由选项 opts 定义的操作 |
一个参变量格式 DeviceClassRegister["class",opts] 创建一个典型的驱动程序,两个参变量格式 DeviceClassRegister["class","parent",opts] 实现基本的继承并允许你扩展父类而无需重复它的定义.
DeviceClassRegister 的选项决定各种设备和驱动程序的属性,并定义框架将调用的函数,以便发现设备的类,执行一般设备预期执行的操作,例如:打开设备的连接,进行配置,读入并写入设备,执行命令,关闭设备的连接,以及释放外部的资源.
选项 | 默认值 | |
"FindFunction" | {}& | 如何发现设备 |
"OpenFunction" | None | 打开设备执行的函数 |
"ConfigureFunction" | None | 如何配置设备 |
"ReadFunction" | None | 如何从设备中读取 |
"ReadBufferFunction" | None | 如何从设备缓冲区中读取 |
"WriteFunction" | None | 如何写入设备 |
"WriteBufferFunction" | None | 如何写入设备缓冲区 |
"ExecuteFunction" | None | 如何在设备中执行命令 |
"ExecuteAsynchronousFunction" | None | 如何异步执行命令 |
"CloseFunction" | None | 关闭设备执行的函数 |
"Properties" | {} | 标准化的属性 |
"DeviceIconFunction" | None | 如何为设备对象创建图标 |
"DriverVersion" | Missing["NotAvailable"] | 驱动程序的版本号 |
选项 | 默认值 | |
"OpenManagerFunction" | None | 执行打开设备管理器的函数 |
"MakeManagerHandleFunction" | Identity | 如何为设备管理器创建句柄 |
"PreconfigureFunction" | {}& | 如何预配置一个新设备 |
"ReleaseFunction" | Null& | 如何处理设备管理器对象 |
"ReadTimeSeriesFunction" | Automatic | |
"StatusLabelFunction" | Automatic | 如何为设备对象创建状态标签 |
"NativeProperties" | {} | 原始属性 |
"NativeMethods" | {} | 原始方法 |
"GetPropertyFunction" | DeviceFramework`DeviceGetProperty | 如何获取标准化属性 |
"SetPropertyFunction" | DeviceFramework`DeviceSetProperty | 如何设置标准化属性 |
"GetNativePropertyFunction" | Automatic | 如何获取原始属性 |
"SetNativePropertyFunction" | Automatic | 如何设置原始属性 |
"NativeIDFunction" | None | 如何获取设备的原始 ID |
"OpenReadFunction" | None | 如何打开与设备关联的输入流 |
"OpenWriteFunction" | None | 如何打开与设备关联的输出流 |
"DeregisterOnClose" | False | 是否在设备关闭后注销设备 |
"Singleton" | Automatic | 为多个设备创建规则 |
下一节将详细讨论 DeviceClassRegister 的选项. 与其他 Wolfram 语言选项一样,没有任何一个 DeviceClassRegister 选项是强制性的,在一个特定的驱动程序实现中,其中的许多选项会被省略.
BeginPackage["MyDevice`"]
Begin["`Private`"]
read[__] := XXXXX
DeviceFramework`DeviceClassRegister["MyDevice", "ReadFunction" read]
End[]
EndPackage[]
为了自动被框架发现, class 的 DeviceClassRegister["class",…] 语句必须存在于 Wolfram 语言程序包 class.m 中. 注意该命名规则,DeviceClassRegister 的第一个字符串参数必须与驱动程序文件名匹配. 另外,驱动程序必须放在下列位置之一:
- 在当前运行的笔记本目录(NotebookDirectory)
- 在计算机系统中指定的目录 FileNameJoin[{$InstallationDirectory,"SystemFiles","Devices","DeviceDrivers"}]
- $Path 中的任何位置
- 在数据包的服务器或在驱动程序的数据包目录(参见“开发设备驱动程序数据包”)
如果驱动程序没有遵循这个规则,它仍然可以被使用,但是它必须被明确加载进 Wolfram 语言会话中,例如,使用 Get.
DeviceClassRegister 的选项,也被称为设备驱动程序选项,允许您创建适合设备的驱动程序. 包含“Function”(驱动程序函数)单词的驱动程序选项的名称大致对应于用户级函数. 比如,"ConfigureFunction" 在执行 DeviceConfigure 时被调用,"FindFunction" 在 FindDevices 中被调用等. 然而,也有用户级函数跨越多个驱动程序函数,如下所示. 其中一个例子是设备打开序列,在 DeviceOpen 中执行,包含 "OpenManagerFunction"、"MakeManagerHandleFunction"、"OpenFunction" 和 "PreconfigureFunction".
提供给许多驱动程序函数的第一个参量是 {ihandle, dhandle} 形式的列表,其中 ihandle 是初始化对象的句柄(或管理器句柄,参阅 "MakeManagerHandleFunction"),dhandle 是设备句柄(参阅 "OpenFunction"). 这个规则应用于 "ConfigureFunction"、"ReadFunction" 和其他驱动程序函数,让你使用任何必要的句柄,跳过其他句柄. 比如,如果你只需要 ihandle,则驱动程序函数会实现为 f[{ih_, _}, args___]:=(* use ih *);若只用 dhandle,你只需为 f[{_, dh_}, args___]:=… 提供规则;若要跳过这两个句柄,使用 f[_, args___]:=…,等等. 在下文中你会发现很多这样的用法.
剩下的提供给驱动程序函数的参变量一般是从父顶层函数传过来,可能从列表封装中剥离. 例如,对于 DeviceRead[dev,param] 和 DeviceRead[dev,{param}],"ReadFunction"f 的实现会收到一个像 f[handles,param] 的调用;对于 DeviceRead[dev,{param1,param2,…}],函数会被调用为 f[handles,param1,param2,…];对于 DeviceRead[dev],调用形式为 f[handles],等等. 你应该期待所有父函数文档描述的组合可能,如果某些组合没有意义,会发出适当的错误信息. 如果失败,驱动程序函数会返回 $Failed,除非那些在本教程中特殊指出的.
当报告错误时,如果你的驱动程序导出这样的符号时,习惯上,它会与你自己的用户可见符号关联信息. 或者,你可以为你的类分配信息给特殊的符号 DeviceFramework`Devices`class. 该教程给出这个规范的一些例子. 欲了解更多,请参阅 "消息".
在阅读本教程时,你已经注意到,大部分例子只是应用顶层的 Wolfram 语言指令. 这是有意这么做的,这样你可以重新计算范例,没有任何指定设备可以学习使用“框架”. 实际上的驱动程序会,当然会调用外部程序. 请参阅 "调用外部程序" 获取概述以及下面的“范例”了解典型的应用.
除了本教程的范例,你还可以参考 Wolfram 语言文档中的演示驱动程序实现. 例如,想知道如何实现 "ExecuteAsynchronousFunction",请参见 DeviceExecuteAsynchronous 的演示驱动程序.
执行下面命令,查验 "ExecuteAsynchronousFunction" 的演示实现:
"FindFunction"
为了让你的驱动程序可被发现,你的驱动程序必须有 "FindFunction" 选项. "FindFunction"f 指定 f[] 应被 FindDevices[class] 调用来找到给定类的设备. 函数 f 不接收参变量,应该返回 {{arg11,arg12,…},{arg21,arg22,…},…} 形式的输出,其中 {argi1,argi2,…} 是参变量的列表,它可以提供给 DeviceOpen[class,{argi1,argi2,…}] 以便打开设备号 i.
"OpenManagerFunction"
"OpenManagerFunction"f 指定 f[args…] 应该在设备打开序列开始时被调用,以便创建一个初始化对象,它也被称为“驱动程序管理器”. args 与用户提供给 DeviceOpen["class",{args…}] 的一样. 在设备寿命周期结束时,取消初始化设置阶段,返回的值会传给 "ReleaseFunction". 使用 DeviceInitObject 在设备关闭前的任何时间获取初始化对象.
您可能希望向指定 "OpenManagerFunction",例如,打开一个与外部程序的 WSTP 连接. 在这种情况,该函数将返回一个 LinkObject,您可以在 "ReleaseFunction" 中用 LinkClose 关闭.
"MakeManagerHandleFunction"
您可以通过指定 "MakeManagerHandleFunction"f 创建一个单独的句柄来初始化对象(管理器句柄). 函数 f[obj] 在 "OpenManagerFunction" 之后被调用,并提供由 "OpenManagerFunction" 创建的初始化对象 obj . 返回的值被假设为管理器句柄. 如果没有 "MakeManagerHandleFunction",管理器句柄自身会被假设为初始化对象. 管理器句柄会被传给许多驱动程序函数,作为第一个参数的一部分(见下文).
管理器句柄的例子可以是插座句柄或一个 .NET 对象.
"OpenFunction"
由 "OpenFunction"f 指定的函数是由框架调用的主函数,对应于用户对 DeviceOpen 的调用. f[ihandle,args…] 接收由 "MakeManagerHandleFunction" 创建的的管理器句柄 ihandle 以及用户提供给 DeviceOpen["class",{args…}] 的参数 args . 返回值被称为“设备句柄”. 此句柄以及管理器句柄会被传给许多驱动程序函数. 另外,您可以用 DeviceHandle 进行检索.
框架尝试在由 "OpenFunction" 返回的设备句柄以及由 DeviceOpen 返回的顶级 DeviceObject 间维持一对一的响应. 因此强烈建议您的设备句柄是唯一的或至少不会与由其他你无法控制的驱动程序创建的句柄相冲突. 一个简单的实现方法就是用 CreateUUID 产生您的句柄. 或者,您可以以 "com.company.class"[… ] 形式或类似方法返回句柄.
"OpenReadFunction"
"OpenReadFunction"f 指定 f[{ihandle,dhandle},args…] 应该在设备打开序列期间被调用,在 "OpenFunction" 之后,打开任何与设备相关联的输入流. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 参变量 args 是那些提供给 DeviceOpen["class",{args…}] 的. 返回值必须是输入流对象或输入流对象列表.
"OpenWriteFunction"
"OpenWriteFunction"f 指定 f[{ihandle,dhandle},args…] 应该在设备打开序列期间被调用,在 "OpenFunction" 之后,打开任何与设备相关联的输入流. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 参变量 args 是那些提供给 DeviceOpen["class",{args…}] 的. 返回值必须是输入流对象或输入流对象列表.
"PreconfigureFunction"
由 "PreconfigureFunction"f 指定的函数决定设备打开序列. 对于将返回给用户的设备对象 dev,f[dev] 被保证在成功调用 DeviceOpen 之后被调用,但是在初始化配置之前,重新应用于设备的顶层设备属性(如果之前在设备中被设置过)或设置 类属性(如果由驱动程序定义). "PreconfigureFunction" 必须通过 "PreconfigureFunction" 自身、"OpenFunction"或在设备打开序列中的任何其他函数返回由驱动程序配置的属性清单. 这些属性不会被框架改变直到 DeviceOpen 结束. 会返回 All 或 None.
"ConfigureFunction"
"ConfigureFunction"f 指定 f[{ihandle,dhandle},args…] 应该被调用以便响应顶层命令 DeviceConfigure[dev,{args…}] 来配置设备. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 该函数的返回值被忽略.
通过调用 DeviceConfigure 打开设备并配置:
"ReadFunction"
"ReadFunction"f 指明 f[{ihandle,dhandle},args…] 应该被调用以响应顶层命令 DeviceRead[dev,{args…}] 来从设备中读取数据. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 该函数的返回值会作为 DeviceRead[] 命令的输出传递给用户.
打开设备并用合法参变量调用 DeviceRead:
用非法参变量调用 DeviceRead,触发错误:
"ReadBufferFunction"
"ReadBufferFunction"f 指定 f[{ihandle,dhandle},…] 应被调用以便响应顶层命令 DeviceReadBuffer[dev,args…],从设备缓存中读取数据. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 传给函数 f 的参变量如下:
DeviceReadBuffer[dev] |
f[{ihandle,dhandle},Automatic]
|
DeviceReadBuffer[dev,crit] |
f[{ihandle,dhandle},crit,Automatic]
|
DeviceReadBuffer[dev,crit,params] |
f[{ihandle,dhandle},crit,params]
|
"WriteFunction"
"WriteFunction"f 指明 f[{ihandle,dhandle},args…] 应被调用以便响应顶层命令 DeviceWrite[dev,{args…}],把数据写入设备. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 该函数的返回值被忽略.
该驱动程序为每个 DeviceWrite 的调用创建一个新笔记本:
"WriteBufferFunction"
"WriteBufferFunction"f 指明 f[{ihandle,dhandle},args…] 应被调用以响应顶层命令 DeviceWriteBuffer[dev,{args…}],把数据写入设备缓存. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 该函数的返回值被忽略.
"ExecuteFunction"
"ExecuteFunction"f 指明 f[{ihandle,dhandle},"command",args…] 应被调用以响应顶层命令 DeviceExecute[dev,"command",{args…}],在设备中执行命令. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 该函数的返回值会传给用户作为 DeviceExecute[] 命令的输出.
"ExecuteAsynchronousFunction"
"ExecuteAsynchronousFunction"f 指明 f[{ihandle,dhandle},"command",args…,fun] 应被调用以响应顶层命令 DeviceExecuteAsynchronous[dev,"command",{args…},fun],在设备上开始异步执行指定的命令. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 函数 f 一般会把用户指定的句柄函数 fun 传给下流,当事件发生时被执行. f 的返回值应该是 AsynchronousTaskObject[] 或类似的对象,会传给用户作为 DeviceExecuteAsynchronous[] 命令的输出.
如果 command 不被支持,函数 f 必须产生一个 Missing[] 对象或简单返回未计算的值. 不管怎样,框架会产生一个合适的信息. 如果是其他错误,f 必须产生合适的信息并返回 $Failed. 尤其是,如果指定的带有给定参变量的命令不能被执行.
"CloseFunction"
"CloseFunction"f 指明 f[{ihandle,dhandle}] 应被调用以响应顶层命令 DeviceClose[dev],关闭设备并释放相关资源. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 该函数的返回值会传给用户作为 DeviceClose[] 命令的输出. 成功完成后,期待为 Null.
"CloseFunction" 一般包括关闭所有端口和套接口并释放其他资源,除了那些在 "ReleaseFunction" 中关闭的. 在 "OpenReadFunction" 和 "OpenWriteFunction" 中打开的流会自动被框架关闭,证明它们可以使用 Close 关闭. 如果不是那样,你应该在 "CloseFunction" 中关闭流.
关闭的设备仍然在当前 Wolfram 语言会话中可用. 使用 "DeregisterOnClose" 在关闭后完全去除设备.
"ReleaseFunction"
"ReleaseFunction"f 指明 f[obj] 应在 "CloseFunction" 之后被调用,在 DeviceClose 操作期间,破坏由 "OpenManagerFunction" 创建的初始化对象 obj,必要的话并执行其他剩下的清扫任务. 该函数的返回值被忽略,除非它是 $Failed.
"DeregisterOnClose"
"DeregisterOnClose"True 指明 DeviceClose 应该不只是释放所有外部资源,并要从当前 Wolfram 语言会话中完全去除设备. 默认情况下,使用 "DeregisterOnClose"False,设备仍然可用,并可以用同样的参数重新开启.
"Singleton"
调用具有同样参变量的 DeviceOpen 给出同样的设备:
重要的是,如果不需要打开一个新设备响应 DeviceOpen,框架一般不会执行驱动函数的打开序列,包括 "OpenFunction". 然而,如果指定的标准 crit 返回 True,它会执行打开序列,但是参变量 args 不完全匹配先前打开设备的参变量. 这样让你为不同的参变量集合重新配置同样的设备.
使用该驱动程序,DeviceOpen 对每个不一样的第一个参变量返回一个新的设备:
"Properties"
选项 "Properties"{"property1"value1,"property2"value2,…} 指定 类属性,一般决定新创建设备的标准的(顶层)属性. 标准的属性名称通常以字符串形式给出. 驱动程序也可以指定 本地属性.
"GetPropertyFunction"
"GetPropertyFunction"f 指明 f[dev,p] 应被调用,查询设备 dev 的标准属性 p 的值. 返回值会传给用户. "GetPropertyFunction" 的默认值是 DeviceGetProperty,你可以在函数 f 内调用.
"SetPropertyFunction"
"SetPropertyFunction"f 指明 f[dev,p,val] 应被调用设置设备 dev 的标准属性 p 为值 val. f 的返回值被忽略. "SetPropertyFunction" 的默认值是 DeviceSetProperty,你可以在函数 f 内调用.
高级主题:保持顶层属性与设备同步
"NativeProperties"
选项 "NativeProperties"{property1,property2,…} 指明本地属性列表,一般在给定类的设备上可用. 当你希望以由框架提供的标准方式访问你的设备并希望有选项可以直接与设备工作,本地属性很有用. 本地属性的名称一般是由不受你控制的第三方程序库定义. 它们可以是任何“合理的” Wolfram 语言表达式.
举例来说,你可能想为一个通过 .NET/Link 连接的设备使用 DeviceOpen、DeviceRead、DeviceExecute 以及其他标准 Wolfram 语言函数设置一个驱动程序,并且同时让你的用户通过 .NET/Link 接口与设备直接通信.
"GetNativePropertyFunction"
"GetNativePropertyFunction"f 指明 f[dhandle,p] 应被调用,通过设备句柄 dhandle 查询设备的本地属性 p 的值. 函数 f 应返回属性值. 默认值 Automatic 本质上等价于 Function[{dhandle,p},dhandle@p].
"SetNativePropertyFunction"
"SetNativePropertyFunction"f 指明 f[dhandle,p,val] 应被调用,设置由设备句柄 dhandle 识别的设备上的本地属性 p 值为 val. 函数的返回值被忽视. 默认值 Automatic 本质上等价于 Function[{dhandle,p,val},dhandle@p=val].
"StatusLabelFunction"
默认情况下,框架使用 DeviceDefaultStatusLabels[] 为由 DeviceOpen[class] 打开的设备创建状态标签,DeviceDefaultStatusLabels[p] 用于在 DeviceOpen[class,{p,…}] 中带有参数 p 的设备. 你可以使用选项 "StatusLabelFunction"f 创建你自己的标签. 函数 f[{args}] 会在设备准备阶段被调用,其中参变量 args 由 DeviceOpen["class",{args…}] 提供. 它必须返回一个字符串,为一个打开的设备替代标签或两个字符串 {olbl,clbl} 列表,标签 olbl 替代打开的设备,标签 clbl 替代关闭的设备.
"DeviceIconFunction"
"DeviceIconFunction"f 指明 f[{ihandle,dhandle},args…] 应被调用,为因响应DeviceOpen["class",{args…}] 而创建的设备对象创建一个自定义图标. 第一个参量 {ihandle,dhandle},是许多驱动程序函数常见的参量,其中 ihandle 是管理器句柄,dhandle 是设备句柄. 函数必须返回一个 Graphics 对象.
"DriverVersion"
可以用 DeviceDriverVersion 获取已加载驱动程序的版本号.
在 DeviceClassRegister 内部,它会调用 DeviceClassClear,并在创建任何新类前,有效地去除所有存在的对指定类的定义,因此当开发驱动程序时,你可以安全地多次调用 DeviceClassRegister.
使用驱动程序文件
DeviceFramework`FindDeviceDrivers[form] | |
给出名称匹配字符串模式 form 的类的驱动程序列表 | |
DeviceFramework`DeviceDriverLoad[class] | |
发现并加载指定类的驱动程序 | |
DeviceFramework`DeviceDriverFile[dev class] | |
为设备 dev 或类 class 提供当前注册的驱动程序的路径 | |
DeviceFramework`DeviceDriverPaclet[dev class] | |
为设备 dev 或类 class 提供当前加载的数据包驱动程序的数据包对象 | |
DeviceFramework`DeviceDriverVersion[dev class] | |
为设备 dev 或类 class 提供当前加载的驱动程序的版本号 |
FindDeviceDrivers 以 {"path/to/driver",class,version} 形式返回三元组列表. 你可以使用此信息检查驱动程序文件,而无需加载到 Wolfram 语言会话,比较不同的驱动程序版本,或加载先前的驱动程序版本,而非最近版本,均可以由 DeviceOpen 自动加载.
对于已加载的驱动程序,你可以使用 DeviceDriverFile 找到确切的加载文件. 这个很有用,如果你的驱动程序有多个实现,并想确保框架加载了正确的版本;或者在重新编辑后,重新加载驱动程序;或只是学习驱动程序实现的细节.
访问关于设备的用户可视信息
DeviceFramework`DeviceClass[dev] | 返回设备 dev 的类 |
DeviceFramework`DeviceID[dev] | 返回设备 dev 的 ID |
DeviceFramework`DeviceStatusLabels[dev],DeviceFramework`DeviceStatusLabels[dev]={olbl,clbl} | |
为设备 dev 的打开和关闭状态,获取和设置状态标签 |
你可以在设备运行的任何时间改变状态标签. 新的标签会在下次前端为你的设备对象创建用户界面时被显示. 因此,你会在设备首次呈现给用户前在 "PreconfigureFunction" 创建自定义的状态标签.
访问关于设备的内部信息
DeviceFramework`DeviceInitObject[dev] | |
返回设备 dev 的初始化对象 | |
DeviceFramework`DeviceManagerHandle[dev] | |
返回设备 dev 的初始化对象的句柄 | |
DeviceFramework`DeviceHandle[dev] | 返回设备 dev 的句柄 |
DeviceFramework`DeviceObjectFromHandle[h] | |
返回句柄 h 的设备对象 | |
DeviceFramework`DeviceOpenArguments[dev] | |
返回打开设备 dev 的参量 | |
DeviceFramework`DeviceDriverOption[class,"opt"],DeviceFramework`DeviceDriverOption[class,"opt"]=val | |
获取和设置指定类的设备驱动程序选项 "opt" 的值 |
虽然 DeviceDriverOption 可以在任何时候被调用,但是在派生类中调用父函数尤其有用.
DeviceDriverOption 还让你在操作设备时,动态改变驱动程序函数值.
最初,此类的设备读取提供给 DeviceRead 的正弦参数:
类属性
当框架需要在特殊的 DeviceObject 中分配标准属性时,它从类属性中取值. 类属性由 DeviceClassRegister 的选项 "Properties" 指定,在加载驱动程序后的任何时间均可以被访问.
DeviceFramework`DeviceClassProperties[class] | |
对指定的类返回可用属性列表 | |
DeviceFramework`DeviceClassProperties[class,prop] | |
对指定的类返回属性 prop 的值 | |
DeviceFramework`DeviceClassProperties[class,{p1,p2,…}] | |
返回多个属性的值 | |
DeviceFramework`DeviceClassProperties[class,prop]=val,DeviceFramework`DeviceClassProperties[class,{p1,p2,…}]={v1,v2,…} | |
设置指定属性的值 |
类偏好设置
类偏好设置,通过 DeviceClassPreferences 访问,是一个更灵活的类存储,在 Wolfram 语言会话中是一致的. 偏好设置是独立于设备驱动程序,因此你可以在加载驱动程序之前、之后或甚至不加载驱动程序时,调用 DeviceClassPreferences;此调用不需加载驱动程序.
DeviceFramework`DeviceClassPreferences[class] | |
返回指定类的可用偏好设置的关联 | |
DeviceFramework`DeviceClassPreferences[class,pref] | |
返回指定类的偏好设置 pref 的值 | |
DeviceFramework`DeviceClassPreferences[class,{p1,p2,…}] | |
返回多个偏好设置的值 | |
DeviceFramework`DeviceClassPreferences[class,pref]=val,DeviceFramework`DeviceClassPreferences[class,{p1,p2,…}]={v1,v2,…} | |
设置指定偏好设置的值 | |
DeviceFramework`DeviceClassPreferences[class]=assoc | |
给 assoc 分配类偏好设置 | |
DeviceFramework`DeviceClassPreferences[class]=.,DeviceFramework`DeviceClassPreferences[class,pref]=.,DeviceFramework`DeviceClassPreferences[class,{p1,p2,…}]=. | |
清除类偏好设置或去除指定的密钥 |
类偏好设置的关联可以包含任意密钥值对. 它们总是在 DeviceClassRegister 的开端进行内部检查. 如果偏好设置恰巧包含对应于 DeviceClassRegister 选项的密钥,它们的值优先于在驱动程序中指定的选项.
保存类的 "Properties" 偏好设置:
当驱动程序一旦被创建,就会使用偏好设置的值,而不是在 DeviceClassRegister 声明中描述的值,在这种情况下,从父类中调用简单的复制属性:
默认属性句柄
DeviceFramework`DeviceGetProperty[dev,prop] | |
为 "GetPropertyFunction" 执行默认的句柄 | |
DeviceFramework`DeviceSetProperty[dev,prop,val] | |
为 "SetPropertyFunction" 执行默认的句柄 | |
DeviceFramework`DeviceDefaultStatusLabels[] | |
给出默认的打开和关闭状态标签的列表 | |
DeviceFramework`DeviceDefaultStatusLabels[p] | |
给出基于参数 p 的默认状态标签 |
决定设备状态
顶层函数 DeviceOpen、DeviceClose、DeviceOpenQ 和 Devices 分别是打开、关闭、测试和给出当前会话中所有注册设备的清单(无论设备是开启或关闭的). 框架还会为模拟提供多个补充函数,但是不常见的操作.
DeviceFramework`OpenDevices[] | 当前打开设备的列表 |
DeviceFramework`DeviceRegisteredQ[dev] | |
测试设备 dev 是否在当前 Wolfram 语言会话中注册 | |
DeviceFramework`DeviceDeregister[dev] | |
注销和完全从当前会话中去除设备 dev |
如果设备是开的,DeviceDeregister 也关闭设备. 当开发驱动程序,清除记录时,该函数很有用.
如要创建一个设备驱动程序数据包,则要包括一个在设备驱动程序根目录下的特定的文件 PacletInfo.m,并行于设备驱动程序文件. 一般来说,驱动程序数据包的名称是带有前缀 “DeviceDriver_” 的驱动程序类名称,例如,“DeviceDriver_MyDevice”. 如需要可在驱动程序根目录中包括其他支持文件和目录.
Tinker Forge Weather Station
Tinker Forge Weather Station 通过迷你 USB 电缆连接至计算机,并由四个被 32位 ARM 微控制器控制的氛围传感器(温度、压强、湿度和光照度)组成. 该设备带有一个显示字符串的 20×4 字符液晶显示屏. 每个传感器(气压计、湿度和光照度)以及液晶显示屏被当作一个子设备或 "bricklet" 共享一个平台组成一个 "Tinker Forge Weather Station" 设备. 设备上的读取命令被认为是从感应器中读取测量结果,编写命令被翻译成在液晶显示屏上显示字符的请求.
假设所有底层设备通讯函数是用 Tinker Forge's C/C++ API 绑定的 C 语言编写的,所有结果 .c 源文件被编译成一个可执行文件. 因此,为了让 Wolfram 语言与该设备通讯,第一步是 Install 该可执行文件,它可以很方便地在"OpenManagerFunction" 中完成. 驱动程序还卡伊实现多个其他函数,如下所示:
DeviceFramework`DeviceClassRegister["myTinkerForge",
"OpenManagerFunction" (Install["\path\to\tinkerforge\executable"]&),
"ReleaseFunction" release,
"MakeManagerHandleFunction" make,
"OpenFunction" open,
"ReadFunction" read,
"WriteFunction" write,
"CloseFunction" close
]
"OpenManagerFunction" 中的 Install 语句一般返回 LinkObject,其中 LinkClose 在 "ReleaseFunction" 中被调用,在去初始化阶段关闭 WSTP 连接.
release[link_] := LinkClose[link]
下面,"MakeManagerHandleFunction" 返回一个句柄给一个 IP 连接对象,表示在控制 C 程序和设备间的 TCP/IP 连接.
make[___] := Tinkerforge`IPConnectionCreate[]
连接句柄 ipconn 作为设备管理器句柄 ihandle 并传给 "OpenFunction",它可用于连接独立的小程序块,为每个创建独立的句柄,并返回这些句柄的列表. 该列表被作为一个复合的设备句柄 dhandle. 在这个气象站中,气压计小程序块读取气压和温度,因此四个传感器有三个有效的小程序块.
open[ipconn_, ___] := {
LightSensorCreate[ipconn],
HumiditySensorCreate[ipconn],
BarometerCreate[ipconn]
}
read[{_, {lightHandle_, humHandle_, baroHandle_}}, rest___] := XXX
write[{ipconn_, _}, rest___] := XXX
最后,"CloseFunction" 将断开 IP 连接并销毁传感器小程序块的句柄.
close[{ipconn_, {lightHandle_, humHandle_, baroHandle_}}] := (
Tinkerforge`IPConnectionDisconnect[ipconn];
LightSensorDestroy[lightHandle];
HumiditySensorDestroy[humHandle];
BarometerDestroy[baroHandle];
)
此外,还有一个更详细的 Tinker Forge Weather Station 驱动程序.
如果您有兴趣为 Wolfram 语言开发和分发设备驱动程序,请联系 Wolfram Research.