正在查看旧版本。 查看 当前版本.

与当前比较 查看页面历史记录

« 前一个 版本 2 当前 »

1 开发准备

  1. 使用PyCharm开发环境进行Python的开发。PyCharm可以使用3.4绿色版,也可以使用其他版本。


  1. eview内置的python为7版本,因此PyCharm配置时也需要使用Python2.7版本。且Python2.7版本根据eview是32位还是64位选择正确版本。
  2. 先安装7,再安装pycharm,pycharm能自动找到python的目录。


  1. 例子代码在开发包的source\drivers\samplepythondrv\samplepythonrv.py文件,运行时直接拷贝py或.pyo文件(python编译后自动生成的一个中间字节码文件)到linux或windows对应目录下(如这里是: eivew\bin\drivers\samplepythondrv\)。


  1. 实际驱动如xxxxdrv请将samplepythonrv目录下的py,替换为xxxxdrv.py,并将samplepythonrv目录改为xxxxdrv名称。
  2. 程序运行时,调用的是eview根目录下的python目录中python库和第三方库。所以如果需要向python中添加第三方库,需要用anconda的pip下载和安装好后,再将下载到python安装目录的 Lib/site-packages下的对应一个或多个目录复制eview根目录的到python/Lib/site-packages下。如果第三方组件还依赖于一些pyd文件,也需要从相应复制过去。

2 驱动的调试运行

2.1 在配置中配置驱动

  • 增加驱动基本信息

进入配置界面->设备配置->系统配置,在对话框中添加驱动。

其中驱动名称为用户自定义的英文驱动名。

或者在数据库eview.db中t_device_driver表增加一条记录,id自动生成(这里为:200001),name和modulename为xxxxdrv。

  • 添加设备

添加驱动配置后,可在设备中增加该驱动的一个设备.

在数据库t_device_list表中增加一条记录,id自动生成(这里为113),name为:xxxxdevice,driver_id:200001,conntype:tcpclient,connparam:ip=127.0.0.1;port=502;


  • 添加变量

添加设备配置后,可在设备中增加一个变量.

在数据库t_device_tag表中增加一条记录,id自动生成,name为:pytag2,device_id:113,address:AI:10;datatype:int16;pollrateMS:1000

2.2 调试准备

  • 将驱动二次开发包下的bin目录下的exe拷贝到“eview安装路径\bin\drivers\xxxxdrv\”路径下;
  • 重命名exe为“xxxxdrv.exe”
  • 安装pycharm并设置python路径后,打开xxxxdrv.py文件。
  • Debug时,启动程序输入:eview安装路径\bin\drivers\xxxxdrv\exe,启动调试,设置对应断点,就可以进行调试了

2.3 驱动调试

2.3.1 调试

驱动配置部署后,eview会自动启动你的驱动程序。调试前需要先关闭你的驱动程序,因为系统仅仅允许启动你的一个驱动进程,停止驱动的方法如下:任务管理器杀掉该驱动。


2.4 运行驱动

直接点击xxxxdrv.exe启动驱动。或者通过pkservermgr自动启动所有程序包括驱动。

3 驱动框架实现的主要功能

驱动框架实现的主要功能如下:

  1. 实现了驱动配置的自动加载读取
  2. 对于TCPServer、TCPClient、UDP、串口,根据配置自动建立、断开和管理与设备的连接状态


4 xxxxdrv.py驱动用到的对象定义

4.1 变量Tag点定义

代表每个变量,在pkDevice的vecTags中包含了所有该设备的tag点对象,可以用的属性如下:

name, 变量名称

address,变量地址

datatype,数据类型,整数

pollrate,轮训速度,整数

lenbits,占用长度,单位:bit

 

4.2 pkDevice

代表每个配置的设备,可以用的属性如下:

name, 设备名称

desc,设备描述

conntype,通讯连接类型,tcpclient,udp,tcpserver,other,serial

conntimeout,通讯连接超时时间

recvtimeout,接收超时时间

connparam,通讯连接参数内容,如ip=192.168.10.2;port=502

param1,设备参数1

param2,设备参数2

param3,设备参数3

param4,设备参数4

tags, 保存有tag点的各个名字的List

driver,设备对应driver对象,具体见下面

4.3 pkDriver

代表每个配置的设备驱动信息,可以用的属性如下:

name, 驱动名称

desc,驱动描述

param1,设备参数1

param2,设备参数2

param3,设备参数3

param4,设备参数4



5 编写xxxxdrv.py中的函数

示例代码(必须如下头部定义):

#! /usr/bin/python
# coding=utf-8

import sys
import struct
import os
sys.path.append(os.path.abspath('.') + '\\..\\..')
sys.path.append(os.path.abspath('.') + '\\..\\..\\python')
import pydriver

def InitDriver(pkDriver):
    print "----InitDriver----"
    print(pkDriver)
    return 0

def UnInitDriver(pkDriver):
    print "----UnInitDriver----"
    print(pkDriver)
    return 0

def InitDevice(pkDevice):
    print "----InitDevice----"
    print(pkDevice)
    tags=[]
    for tag in pkDevice['tags']:
        tags.append(tag)
    timerObj=pydriver.CreateTimer(pkDevice, 3000, tags)
    return 0

def UnInitDevice(pkDevice):
    print "UnInitDevice"
    return 0

def OnTimer(pkDevice, timerObj, pkTimerParam):
    print "----OnTimer----"
    tags = pkTimerParam
    print timerObj
    print tags

    id = 1
    tag="100"
    version = 2
    count = 3
    buffer = struct.pack("!H4s2I", id, tag, version, count)

    print "before send..."
    result = pydriver.Send(pkDevice, buffer, 2000)
    print "SendToDevice:",result
    if(result <= 0):
        print "send to device return <-0"
        print "send to device:", len(buffer) , "return :" , result
        return

    retCode, bufferRecv = pydriver.Recv(pkDevice, 10000, 200)
    print "Recv,retcode:", retCode, ",length:",len(bufferRecv)

    if(retCode != 0):
        return

    # 解析数据,得到值
    tagValue =struct.unpack("!H", bufferRecv)
    print "recv tagValue:",tagValue[0]
    #print "recv,id:",id,",tag:",tag,",version:",version,",count:",count

    tagAddr = "AI:10"
    print tagAddr
    tagList = pydriver.GetTagsByAddr(pkDevice, tagAddr)
    pydriver.SetTagsValue(pkDevice,tagList, str(tagValue[0]))
    pydriver.UpdateTagsData(pkDevice, tagList)
    print "-OnTimer- end"
    return 0

def OnControl(pkDevice, pkTag, strTagValue):
    print "-!--OnControl--!-"
    print pkDevice,pkTag
    print "device name:",pkDevice['name'], "tagname:", pkTag['name'], "tagaddress:",pkTag['address'], "tagvalue:",strTagValue
    return 0

#仅供调试使用,可以直接运行这个python文件进行调试
if __name__ == '__main__':
    pkDriver={'name': '', '_InternalRef': 0, 'param4': '', 'param3': '', 'param2': '', 'param1': '', 'type': '', 'desc': ''}
    pkDevice={'recvtimeout': 500, 'name': 'pytestdevice', 'tags': [{'_ctag': 7981384, 'name': 'CELL06_BLD1', 'lenbits': 16, 'datatype': 'uint16', 'address': 'AI:17023', 'pollrate': 3000}, {'_ctag': 7983144, 'name': 'CELL06_BLD2', 'lenbits': 16, 'datatype': 'uint16', 'address': 'AI:17023', 'pollrate': 3000}, {'_ctag': 7984904, 'name': 'CELL06_OKjishu', 'lenbits': 16, 'datatype': 'uint16', 'address': 'AI:17007', 'pollrate': 3000}, {'_ctag': 7986664, 'name': 'CELL06_NGjishu', 'lenbits': 16, 'datatype': 'uint16', 'address': 'AI:17036', 'pollrate': 3000}], '_InternalRef': 7947760, 'driver': {'name': '', '_InternalRef': 0, 'param4': '', 'param3': '', 'param2': '', 'param1': '', 'type': '', 'desc': ''}, 'conntype': 'tcpclient', 'param4': '', 'param3': '', 'param2': '', 'param1': '', 'conntimeout': 3000, 'connparam': 'ip=127.0.0.1;port=502', 'desc': ''}
    InitDriver(pkDriver)
    InitDevice(pkDevice)


主要有以下函数要实现:

5.1 初始化驱动函数

def InitDriver(pkDriver):
    print "----InitDriver----"
    return 0


参数说明:驱动结构体

功能说明:初始化函数,驱动EXE启动时该函数被调用,可在该函数中实现用户自定义初始化操作(例如使用com接口时调用com初始化函数)。

注意:如无特别需要,可以不实现。

5.2 退出驱动处理

def UnInitDriver(pkDriver):
    print "----UnInitDriver----"
    return 0

参数说明:无

返回值:返回0代表成功,其余值为失败

功能:驱动退出时该函数被调用。在该函数中可以释放用户自定义资源、对于非TCP连接设备断开设备连接等操作。

注意:如无特别需要,可以不实现。

1.1 初始化具体设备函数

def InitDevice(pkDevice):
    print "----InitDevice----"
    pydriver.CreateTimer(pkDevice, 3000, '11aabb')
    return 0

参数说明:设备结构体

功能说明:每个设备配置被加载后会调用该初始化函数,可在该函数中实现用户自定义的具体设备相关初始化操作。常用操作包括:创建定时器、自组块等。

注意:必须实现开启定时器的功能,否则无法执行OnTimer函数

5.3 退出具体设备处理

def UnInitDevice(pkDevice):
    print "UnInitDevice"
    return 0

参数说明:无

返回值:返回0代表成功,其余值为失败

功能:驱动退出时该函数被调用。在该函数中可以释放用户自定义资源、对于非TCP连接设备断开设备连接等操作。

注意:可以不实现。


5.4 处理定时数据读取

def OnTimer(pkDevice, timerHandle,periodMS, pkTimerParam):
    print "----OnTimer----"

参数说明:

pkDevice[输入参数]:设备句柄

timerHandle[输入参数]:定时器周期句柄

periodMS [输入参数]:定时器周期句柄

pkTimerParam[输入参数]:定时器周期句柄


返回值:返回0代表成功,其余值为失败

功能说明:该函数会在InitDevice时创建一定周期的定时器(CreateTimer(pDevice,periodMS,timeParam))后自动被调用。对于块设备,轮询周期往往是指块的轮询周期。对于一次读取所有状态的设备,轮询周期是指设备的轮询周期。通常该函数实现如下功能:

1、数据的发送和接收

2、更新变量实时数据的值、数据状态和时间戳

3、对于非tcp通信协议,通常需要在该接口检查连接状态

注意:该函数必须实现


5.5 处理控制命令

def OnControl(pkDevice, tagName, tagValue):
    print "OnControl"
    return 0

参数说明:

pkDevice [输入参数]:设备指针

tagName [输入参数]:变量名称

tagValue [输入参数]:用字符串表示的变量值(如数字16这里传入”16”)

返回值:控制返回结果

功能说明:当有控制命令时该函数被调用,通过该函数向设备下发控制命令

注意:对于需要通过驱动实现控制功能的,该函数必须实现

6 驱动框架提供给驱动调用的对象与接口

6.1 根据变量地址获得变量列表

pydriver.GetTagsByAddr(pkDevice, strTagAddr)

参数说明:

pkDevice [输入参数]:设备对象

strTagAddr[输入参数]:字符串类型的变量地址,如”AI:10”

返回值:返回该设备地址位strTagAddr的List

6.2 设置一组变量的值

pydriver.SetTagsValue(pkDevice,tagList, strTagValue)

参数说明:

pkDevice [输入参数]:设备对象

tagList[输入参数]:变量列表,可能是pydriver.GetTagsByAddr返回的值

strTagValue[输入参数]:字符串类型的变量值,如”1000”

返回值:返回0表示成功


6.3 更新一组变量数据

pydriver.UpdateTagsData(pkDevice, tagList)

pkDevice [输入参数]:设备对象

tagList[输入参数]:变量列表,可能是pkdriver.SetTagsValue之后的变量列表

返回值:返回0表示成功

6.4 创建定时器

pydriver.CreateTimer(pkDevice, periodMS, timerParam)

pkDevice [输入参数]:设备对象

periodMS[输入参数]:数值类型的定时周期,单位:毫秒。如:3000表示3秒

timerParam[输入参数]:自定义的定时器参数,可以是字符串、对象、数值等任意类型,在OnTimer中可以获取到这个参数

返回值:返回定时器句柄(int型)


6.5 销毁定时器

pydriver.DestroyTimer(pkDevice,timerHandle);

pkDevice [输入参数]:设备对象

timerHandle[输入参数]:CreateTimer返回的定时器句柄

返回值:返回0表示成功

6.6 从设备接收多个字节

pydriver.Recv(pkDevice, maxBytes, recvTimeOutMS) 

功能说明:当用户使用TCP、串口、UDP连接时可调用该接口接收设备数据

pkDevice [输入参数]:设备对象

maxBytes[输入参数]:该次接收最多接收的字符字节数

recvTimeOutMS[输入参数]:接收超时时间,单位是毫秒

返回值:二元元组(retcode, buffer)。这里的buffer必须用struct.unpack去解析。如:

retCode, bufferRecv = pydriver.Recv(pkDevice, 102400, 200)


6.7 向设备发送多个字节

pydriver.Send(pkDevice, buffer, sendTimeOutMS)

功能说明:当用户使用TCP、串口、UDP连接时可调用该接口发送数据到设备

参数说明:当前支持TCP作为客户端、服务端、UDP、串口的连接方式。

pkDevice [输入参数]:设备对象

buffer[输入参数]:待发送数据的缓冲区,二进制缓冲区,通过struct.pack 方法返回的二进制缓冲区。len(buffer)可以得到长度

sendTimeOutMS [输入参数]:发送超时时间,单位是毫秒

返回值:返回成功发送的字节数


7 Python帮助

7.1 处理二进制

参考:https://blog.csdn.net/w83761456/article/details/21171085

比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c语言中的结构体.

struct模块中最重要的三个函数是pack(), unpack(), calcsize()

#  按照给定的格式(fmt),把数据封装成字符串(实际上是类似于c结构体的字节流)

pack(fmt, v1, v2, ...)


# 按照给定的格式(fmt)解析字节流string,返回解析出来的tuple

unpack(fmt, string)      


# 计算给定的格式(fmt)占用多少字节的内存

calcsize(fmt)

7.2 字符串拼接

参考:https://blog.csdn.net/w83761456/article/details/21171085

Result=1000

print("SendToDevice:",result)


  • 无标签