茶馆

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
上次说了这次的题目是对PI数据库中的数据进行读取和写入,可是为了等了这么久呢?出了自己比较懒以外,遇到了一点麻烦也是一个原因呢?后面又说

(一)应用SDK从PI数据库读取数据
    我们知道PI数据库的数据分别存储在Snapshot或者Archive中,一个是快照一个是档案文件,这样做是为了方便PI数据库对数据进行压缩.那么 自然对数据库的读取也分为对Snapshot和Archive读取.snapshot和archive的值都是用PIValue的形式表示的, PIValue对象包括了数值和时间。应用SDK从数据库中获取snapshop或者archive的值很简单。
    首先连接数据库,声明一个PIServer:_piServer = piSDK.Servers.DefaultServer;
    然后利用PIServer的Points属性访回一个点的集合,再通过tagName来获取点:PIPoint pt = _piServer.PIPoints[tbxTagName.Text];
   
如果是使用Snapshot,直接声明一个PIValue通过PIPoint的Snapshot属性来返回值:pv = pt.Data.Snapshot;
    然后我们就可以通过PIValue的Value属性和TimeStamp属性来获取snapshot的值和该值对应的时间了。 
        tbxValue.Text = pv.Value.ToString();
        tbxTime.Text = pv.TimeStamp.LocalDate.ToString();

   
如果要读取Archive的值,那么要稍微麻烦一点,应为你要给定读取的时间和模式,PIPoint对象的ArcValue方法是用来获取Archive的值,帮助的说明如下:
       
object.ArcValue TimeStamp, Mode, AsynchStatus
   
这 个应该是VB的语法吧,我们可以看出他有三个参数。第一个是时间,C#中我们可以直接传一个DateTime格式的数据进去,当然你也可以使用 PITime对象表示的时间,或者一个字符串。Mode代表取出的模式,因为PI数据库并不是每个时间都存有数据的,所以在你可以选择模式是读取你输入时 间的当前点,后面一个点,前面一个点或者插值表示的时间。最后一个参数不解,文档里面没有说明,VB的例子则直接没有传这个参数,应该是一个可选参数,我 的处理方法如下。
        RetrievalTypeConstants rtType;
        rtType = (RetrievalTypeConstants)piSDK.PIConstants["RetrievalTypeConstants"][cbxValue.Text].Value;
        pv = pt.Data.ArcValue(dt, rtType, new PISDKCommon.PIAsynchStatus());
   
RetrievalTypeConstants 就是表示存取模式的,我这里使用过一个下拉列表框获得可用的模式的,最后一个参数是通过传一个新的实例下去,这里不知道这样和不合理,反正可以读出数据我就没有管了,又没有达人解释一下怎么处理这种VB的可选参数的情况呢?我学着VSTS的那种Type.Missing又不可以。
    然后读出来的PIValue同样包含一个数值和一个时间,现在我想大家应该理解为什么PIValue里面要包含一个时间了吧。
    我觉得应用SDK很简单,感觉和开发Excel很象,都是调用Com,也挺符合.net的开发习惯的,文档也好,每个对象还有一个详细的VB例子,虽然不是.net的,但是也可以大致了解得差不多。

(二)应用SDK向PI数据库写入数据
    在PIData对象中有一个
UpdateValue方法和UpdateValues方法,顾名思义,一个是更新单个数据,一个是更新一批数据。但是文档里面红红的标着Not Implemented两个单词,心顿时凉了,考虑到文档的版本比我实际使用的SDK版本第一点,去Object Browser里面搜索了一下,果然找到了这个方法
       public virtual void UpdateValue(object newValue, object TimeStamp, PISDK.DataMergeConstants MergeType, PISDKCommon.PIAsynchStatus asynchStatus)
   
这些参数的意思没有文档也挺好理解的,这里就不说了,可是当我尝试用这个方法去更新数据库的时候,一样抛出了
Not Implemented的错误,当时心里非常的郁闷,这个也就是开头我说到的麻烦。我的SDK的版本是1.2.0,问了一个比较有经验的人,他说他没有遇到过不能写入的问题,等有时间去问问他,看看是不是版本的问题,如果有人能写入的,请给我说一下你们的版本;


(三)应用API从PI数据库读取数据
    SDK不行,还好我们还有PI-API,这个感觉和Win32 API挺象的吧,都是一写用C写的函数,PISDK其实就是把PIAPI包装了一下,可惜我对P/Invoke不怎么熟悉,如果大家对这个也不熟悉的话,我觉得这两篇文章还是不错,作为预备知识。
   
在C#中通过P/Invoke调用Win32 DLL
    如何在C#中使用Win32和其他库
    这两篇文章看了我还是颇有收获的,至少知道引用类型在传递的时候不需要ref关键字,因为在.net中本身就是按地址传递的,呵呵,可能是基础知识太差。
    不过看API的文档和SDK的文档相比真是天壤之别,API文档只有一个简单的概述,例子也没有,参数的说明更是往往只有一句话,不过还好吧,我慢慢的试还是试出来了一些。
    对于数据读取和写入还是分为snapshot和archive,就是两个不同的函数,参数也差不多类似。
    PI-API函数是按组分开的,有Point函数,Archive函数和snapshot函数等。
    从archive数据库读取数据有两个,一个是扩展函数,功能多一些,所以我们在这里使用的是扩展函数来读取数据,其文档的声明如下:     
        int32 PIPROC piar_getarcvaluex(
        int32 ptnum,
        int32 mode,
        float64 PIPTR *drval,
        int32 PIPTR *ival,
        void PIPTR *bval,
        uint32 PIPTR *bsize,
        int32 PIPTR *istat,
        int16 PIPTR *flags,
        PITIMESTAMP PIPTR *time);
   
int32,uint32这些都是PIAPI里面自己定义的类型,从名字可以很简单的看出他们对应32位整数,32位无符号整数,在C#中这些,.net已经给我们定制好了,还比较方便。
    PITIMESTAMP 是一个结构体,定义很简单,我们直接在C#中定制一个类似的结构就好了。
    ptnum是PI tag号对应的一个Int32位的整数来代表数据库中的一个点,可以通过API函数pipt_findpoint把Tag名字转换成ptnum。
    mode和SDK里面的模式很类似,就是看是读取前面一个点,还是后面一个点的值。
    如果读取出来的是浮点值,drval就是这个值;
如果读取出来的是整型值,ival就是这个值;bval是一个字符串,bsize是这个字符串的缓冲区大小,istat是代表数值量的值,flags文档上面的说明是

Data quality flag mask不解。time是值对应的时间,相当于SDK里面的pv.TimeStamp.LocalDate。

    对于字符串,这里我看了半天,因为string类型是一个不定长的字符串,所以是不能用在这个地方的,这个地方的bval应该是使用 StringBuilder,StringBuilder.Capacity就表示了bsize,这一点还是冲上面那两篇文章看到的,真是基础差,呵呵。

    对于void指针,我是把它处理成为object类型,因为我们基本上不用到字符串的值,所以这里我也没有测试,达人指导一下,呵呵。综上,我的C#格式的函数是

        [DllImport("piapi32.dll", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern Int32 piar_getarcvaluex(
            Int32 ptnum,
            Int32 mode,
            ref Double drval,
            ref Int32 ival,
            [MarshalAs(UnmanagedType.AsAny)] object bval,
            ref UInt32 bsize,
            ref Int32 istat,
            ref Int16 flags,
            ref PITime.PITIMESTAMP time);

    第五个参数必须Mashall成AsAny类型,要不直接使用object类型是不行的。那么我怎么知道他是Any类型呢?因为文档上面VB的函数调用声明是bVal As Any,这也是一点灵感吧。至于返回的Int32值是代表调用是否成功的,就和win32  API类似吧。



    这次就先写到这里吧,下次待续

    如果大家解决过我不解的问题,先写写了。呵呵!

***********************************************************************************************************************************

    同上一篇,本文谢绝转载.包括网络和其他介质



   



posted on 2006-06-19 17:09  laue  阅读(10168)  评论(12编辑  收藏  举报