1 场景描述
当有外部设备或者外部数据源需要与云表浏览器交换数据时,可以通过云表提供设备监听的SDK来进行扩展开发设备监听程序。监听程序将完成浏览器与设备的“交互”。
设备监听程序可以部署在云表浏览器可以访问到的网段(例如局域网或固定IP的广域网)主机上,设备监听程序与外部设备以何种方式通讯(串口或IP/TCP等)由开发监听程序的人员实现,设备监听程序与浏览器之间的通讯由云表外接设备监听协议实现(已经封装好SDK可用)。
2 云表浏览器与外部设备的通讯
云表浏览器与外部设备的通讯包括设备发送过来的数据以及发送数据到设备。这个通讯过程是由设备监听程序完成的。云表浏览器表单页面可以通过添加填表公式监听外部程序发送过来的数据,外部设备也可以接收来着表单页面的命令。
2.1 监听外部设备发过来的数据
在填表公式中添加外部监听设备,如下图所示
同一个设备监听程序可以有多个事件。如果需要关注多个事件则要添加多个设备监听,使用相同的设备名称(监听程序注册的唯一标识,每个监听程序都需要有一个唯一的标识用于区分不同的设备),再设置关注的事件名称(即图中的数据名称)。
在监听设备下添加填表公式响应外部设备发生过来的数据。例如在监听设备下添加赋值填表公式来取出外部设备数据并赋值到表单上,如下图所示
2.2 发送命令到外部设备
添加发送命令到设备填表公式来发送命令到外部设备。例如发送 Scan 命令到外部设备,下图例子中无参数,也可以设置参数同命令一起发送到外部设备。
3 设备监听程序
设备监听程序可通过对接云表提供的SDK来实现与云表浏览器的数据交换。监听程序发往云表浏览器的数据会在填表公式中的设备监听里作为事件触发相应的填表公式。云表浏览器
也可以通过填表公式发送命令到设备将数据发到设备监听程序,触发监听程序中的命令回调。
3.1 外部设备监听SDK
目前提供的SDK是一个DLL文件(有32位以及64位两个版本)。SDK的目录结构如下:
.\C# C#的demo
.\C++ C/C++的demo
.\Delphi delphi的demo
.\Public DLL sdk的dll,包括32位和64位版本
.\Public DLL\TestTool 用于测试的工具,它相当于云表浏览器(可以接收来自监听程序的事件数据和发送命令数据到监听程序,模拟填报公式的设备监听和发送命令到设备)
3.2 SDK接口函数
函数声明(C/C++)
typedef void(__stdcall* CommandHandler)(void* lpUserData, wchar_t* lpParams);
int __stdcall laInitialize(wchar_t* lpDeviceID);
int __stdcall laAddEvent(wchar_t* lpEventName);
int __stdcall laAddCommand(wchar_t* lpCommand, CommandHandler callback, void* lpUserData);
int __stdcall laServiceStart();
int __stdcall laTriggerEvent(wchar_t* lpEventName, wchar_t* lpDatas);
void __stdcall laServiceStop();
void __stdcall laFinalization();
函数声明(C#)
public delegate void CommandHandler(IntPtr userData, IntPtr Params);
[DllImport("laDeviceSupport.dll", EntryPoint = "laInitialize", CharSet = CharSet.Unicode)]
static extern int Initialize(string deviceID);
[DllImport("laDeviceSupport.dll", EntryPoint = "laFinalization")]
static extern void Finalization();
// 注册设备事件
[DllImport("laDeviceSupport.dll", EntryPoint = "laAddEvent", CharSet = CharSet.Unicode)]
static extern int AddEvent(string eventName);
// 注册设备事件
// eventParams 参数格式为:参数名:类型 组成的JSON
// 类型可取值 String/Integer/BigInt/Float/Double/Boolean/Date/Time/Timestamp/Memo/File
// 例如:
// {"paramName1":"String","paramName2":"Boolean"}
[DllImport("laDeviceSupport.dll", EntryPoint = "laAddEvent2", CharSet = CharSet.Unicode)]
static extern int AddEvent2(string eventName, string eventParams);
// 注册设备命令
[DllImport("laDeviceSupport.dll", EntryPoint = "laAddCommand", CharSet = CharSet.Unicode)]
static extern int AddCommand(string command, CommandHandler handler, IntPtr userData);
// 注册设备命令
// commandParams 参数见 AddEvent2
[DllImport("laDeviceSupport.dll", EntryPoint = "laAddCommand2", CharSet = CharSet.Unicode)]
static extern int AddCommand2(string command, string commandParams, CommandHandler handler, IntPtr userData);
[DllImport("laDeviceSupport.dll", EntryPoint = "laServiceStart")]
static extern int ServiceStart();
[DllImport("laDeviceSupport.dll", EntryPoint = "laTriggerEvent", CharSet = CharSet.Unicode)]
static extern int TriggerEvent(string eventName, string datas);
[DllImport("laDeviceSupport.dll", EntryPoint = "laServiceStop")]
static extern void ServiceStop();
函数声明(Delphi)
const
laDeviceSupport = 'laDeviceSupport.dll';
type
TLatoHandlerProc = procedure(AUserData: Pointer; const AParams: PWideChar); stdcall;
function Initialize(const ADeviceID: PWideChar): Integer; stdcall; external laDeviceSupport name 'laInitialize';
function AddEvent(const AEventName: PWideChar): Integer; stdcall; external laDeviceSupport name 'laAddEvent';
function AddCommand(const ACommand: PWideChar; const AHandler: TLatoHandlerProc; AUserData: Pointer): Integer; stdcall; external laDeviceSupport name 'laAddCommand';
function ServiceStart: Integer; stdcall; external laDeviceSupport name 'laServiceStart';
function TriggerEvent(const AEventName, ADatas: PWideChar): Integer; stdcall; external laDeviceSupport name 'laTriggerEvent';
procedure _Finalization; stdcall; laDeviceSupport name 'laFinalization';
3.3 接口函数说明
除了laInitialize 和 laFinalization 建议在主线程调用以外,其它函数可在任意线程调用
3.3.1 laInitialize
函数声明
int __stdcall laInitialize(wchar_t* lpDeviceID);
函数说明
函数用于初始化sdk,主要是创建线程池、互斥对象以及设备监听服务。该函数建议在主线程调用,建议在程序入口函数调用
参数说明
lpDeviceID
字符串参数,用于作为设备监听唯一标识,不同设备用不同的设备监听标识,该参数也是填表公式里设备监听中的设备名称
3.3.2 laAddEvent
函数声明
int __stdcall laAddEvent(wchar_t* lpEventName);
函数说明
调用初始化函数laInitialize之后,在调用laServiceStart启动服务函数之前调用。函数用于注册设备事件,可以多次调用函数注册多个事件
参数说明
lpEventName
事件名称,该参数也是填表公式里设备监听中的数据名称
3.3.3 laAddCommand
函数声明
typedef void(__stdcall CommandHandler)(void lpUserData, wchar_t lpParams);
int __stdcall laAddCommand(wchar_t lpCommand, CommandHandler callback, void* lpUserData);
函数说明
调用初始化函数laInitialize之后,在调用laServiceStart启动服务函数之前调用。函数用于注册设备命令,可以多次调用函数注册多个命令
参数说明
lpCommand
命令名称,该参数也是填表公式里发送命令到设备中的命令名称
callback
当云表浏览器执行填表公式发送命令到设备时执行回调函数,回调函数中的 lpParams 参数就是填表公式中发送过来的参数,并组织成一个JSON字符串(详情请转到数据规范小节)。
注意:回调函数是在非主线程中调用
lpUserData
回调函数的参数 lpUserData 的值,每次执行回调函数都传入该值
3.3.4 laServiceStart
函数声明
int __stdcall laServiceStart();
函数说明
调用初始化函数,并添加需要的事件和命令后调用该函数开启监听服务,开启服务监听后将无法再注册事件或命令
3.3.5 laTriggerEvent
函数声明
int __stdcall laTriggerEvent(wchar_t* lpEventName, wchar_t* lpDatas);
函数说明
调用该函数触发事件到云表浏览器,从而触发填表公式设备监听中对应的数据名称事件
参数说明
lpDatas
随着事件发送到浏览器并作为设备数据源的数据,内容为一个JSON字符串(详情请转到数据规范小节)
3.3.6 laServiceStop
函数声明
void __stdcall laServiceStop();
函数说明
停止监听服务,调用完该函数后,SDK将不再可用,可以在程序结束时调用 laFinalization 停止服务。
3.3.7 laFinalization
函数声明
void __stdcall laFinalization();
函数说明
停止监听服务,停止线程池服务,释放必要的内存。该函数建议在主线程调用,建议在程序结束时调用
3.4 数据规范
设备数据通过laTriggerEvent将发往云表浏览器,从而触发填表公式的设备监听事件。设备数据需格式化成如下JSON字符串:
{"eversheet":{"version":1,"dataName":"称重"},"dataSet":[{"名称":"铅笔","重量":1},{"名称":"毛笔","数量":3}]}
dataName是填表公式设备监听中的数据名称
dataSet数组中每一个对象将是设备数据源中的一条记录
云表浏览器通过填表公式发送命令到设备将数据发往监听程序,从而触发laAddCommand注册的回调函数,并将参数格式化成如下JSON字符串:
{"参数名":"参数值","开启设备":true}
3.5 SDK例子
相关例子在提供的SDK中,目前有C/C++、C#、Delphi三种语言的Demo,源码中有相关注释,根据自己习惯的编程语言查看相应的例子源码