使用C#進行基於PI的開發


 

首先欲基於PI-SDK開發PI數據庫,必須先安裝PI-SDK,然后再VS中新建了一個aspnet網站,添加引用:PI-SDK 1.2 Type Library 和 PISDKCommon 1.2 Type Library

花了很多時間在PISDK下面找了一個能實例化的類PISDKClass,后來又發現原來Servers 是這個對象的一個屬性.

private PISDK.IPISDK piSDK= new PISDK.PISDKClass();

private PISDK.Server _piServer;

private PISDK.PIPoint _piPoint;

在Page_Load事件枚舉所有的數據源,添加到DropSownlist.

foreach(PISDK.Server item in piSDK.Servers)

{

DropDownList1.Items.Add(srv.Name);

}

設置_piServer為dropdown里面選中的數據庫

_piServer = piSDK.Servers[DropDownList1.Text];

然后下面接着防置一個文本框來讀取用戶輸入的Tag點,Tag有點相當於普通數據庫的字段.但是又不一樣,關於這個暫時不細說了

和一個ListBox來得到這個Tag的所有屬性.代碼如下:

_piPoint = _piServer.PIPoints[tbxTagName.Text];

ListBox1.Items.Clear();

foreach (PISDK.PointAttribute ptatr in _piPoint.PointAttributes)

{

ListBox1.Items.Add(ptatr.Name);

}

讀取Tag屬性的值可以用下述屬性.

tbxAttValue.Text = _piPoint.PointAttributes[ListBox1.Text].Value.ToString();

如果要更新這個屬性的值呢?仍然很簡單

PISDK.PointAttribute ptatr;

_piPoint = _piServer.PIPoints[tbxTagName.Text];

ptatr = _piPoint.PointAttributes[lblAttrName.Text];

_piPoint.PointAttributes.ReadOnly = false;

ptatr.Value = tbxAttValue.Text;

_piPoint.PointAttributes.ReadOnly = true;

blNotion.Text = "更新成功!";

其實最后一句想用MessageBox可惜在asp.net下面一直找不到好的使用MessageBox的方法,原來在CodeProject上面找了一個,但是因為后來發現在Atlas的updatepanel中不能使用,也就作罷了

OK,上面就是我根據SDK-Manual里面的一個Basic例子,用C#改寫了一下,實現了和例子一樣的功能,雖然今天花費了

下面是一個簡單的截圖和SDK截圖的對比:

首先欲基於PI-SDK開發PI數據庫,必須先安裝PI-SDK,然后再VS中新建了一個aspnet網站,添加引用:PI-SDK 1.2 Type Library 和 PISDKCommon 1.2 Type Library

接着看文檔上面VB的例子代碼是

Option Explicit

Dim srv as Server

Dim pt As PIPoint

for Each srv In Servers

Combo1.AddItem srv.Name

Next srv

為了把這兩個地方改成能運行得C#代碼還花費了不少力氣,因為原來沒有做的東西都是很簡單的.net東西,基本上沒有用到過和COM組件進行交互.首先說什么不能實例花,接着又說什么Servers不行,花了很多時間在PISDK下面找了一個能實例化的類PISDKClass,后來又發現原來Servers 是這個對象的一個屬性.

private PISDK.IPISDK piSDK= new PISDK.PISDKClass();

private PISDK.Server _piServer;

private PISDK.PIPoint _piPoint;

在Page_Load事件枚舉所有的數據源,添加到DropSownlist.

foreach(PISDK.Server item in piSDK.Servers)

{

DropDownList1.Items.Add(srv.Name);

}

設置_piServer為dropdown里面選中的數據庫

_piServer = piSDK.Servers[DropDownList1.Text];

然后下面接着防置一個文本框來讀取用戶輸入的Tag點,Tag有點相當於普通數據庫的字段.但是又不一樣,關於這個暫時不細說了

和一個ListBox來得到這個Tag的所有屬性.代碼如下:

_piPoint = _piServer.PIPoints[tbxTagName.Text];

ListBox1.Items.Clear();

foreach (PISDK.PointAttribute ptatr in _piPoint.PointAttributes)

{

ListBox1.Items.Add(ptatr.Name);

}

讀取Tag屬性的值可以用下述屬性.

tbxAttValue.Text = _piPoint.PointAttributes[ListBox1.Text].Value.ToString();

如果要更新這個屬性的值呢?仍然很簡單

PISDK.PointAttribute ptatr;

_piPoint = _piServer.PIPoints[tbxTagName.Text];

ptatr = _piPoint.PointAttributes[lblAttrName.Text];

_piPoint.PointAttributes.ReadOnly = false;

ptatr.Value = tbxAttValue.Text;

_piPoint.PointAttributes.ReadOnly = true;

blNotion.Text = "更新成功!";

其實最后一句想用MessageBox可惜在asp.net下面一直找不到好的使用MessageBox的方法,原來在CodeProject上面

1>應用SDK從PI數據庫讀取數據

上一次的例子是通過PI-SDK獲取Tag的屬性並且修改它,我想更重要的是怎么取出Tag的值和進行更新吧。在進行嘗試之前看了看文檔,了解了一下PISDK的對象結構,下面這一張就是PISDK的結構圖

 

簡要了解在例子中要用到的對象,並把它們的描述進行了簡單的翻譯,我想翻譯的目的應該是幫助自己更好的進行學習,給出英文對照。不妥之處,忘大牛們指正:

 

//**********************正文開始*************************************************/

The Server object represents a single server (data archive). Server objects are retrieved from the Servers collection and provide access to the basic entities represented on each server, such as points, point classes, digital states, users, and groups. Some basic properties are available from the Server object as initially retrieved from the Servers collection.

    Typically a program will require a network connection to the server. Connections are established either by calling the Open method of the Server object explicitly or by accessing a property or calling a method of the Server object that requires server access, forcing an implicit connection.

    Many of the services available through the Server object are accessed through its properties which return other objects. For example, the PIPoints property provides a PIPoints collection object for accessing the various points on a server.

    服務器(Server)對象表示了一個單獨的PI數據庫服務器,服務器對象可從服務器集合中獲得並且提供了訪問每個數據庫中的實體的方法,這些實體包括點,點集合,數字量(開關量),用戶和組。服務器對象提供了一些基本的屬性從而在服務器集合中隊服務器進行初始化。

      一般地,程序連接到服務器需要網絡連接屬性,這個連接可以通過服務器對象的Open方法顯式的進行,也可以通過服務器對象的某個屬性或方法連接需要驗證的服務器來進行一個隱式的連接。

上面這一段有點不太懂,直到目前我都沒有用過顯式的Open方法,都是通過

    _piServer = piSDK.Servers.DefaultServer;

    這種所謂的隱式方法來連接,這個是不是就是所謂的隱式連接?因為在PISDK安裝的時候指定了一個PI數據源,所以DefaultServer就是這個?所以我訪問的時候都不需要輸入用戶或者密碼

       我們可以通過服務器對象的屬性來返回其他的對象從而獲得很多服務。例如,通過服務器對象的PIPoints屬性返回的PIPoints集合的對象來訪問數據庫里面的不同的點。

 

A PIConstant collection maps display strings to PI-SDK enumerations. This provides a way for an application to display strings indicating choices of behavior for a user to select particular actions. The application then retrieves the associated constant and passes it to a particular method being called. A PIConstant collection contains members, stored and accessed as NamedValue objects that represent the display string (the name) and the constant (the value). A PIConstant collection is retrieved using PISDK.PIConstants.Item.

       PIConstant集合映射字符串到PI-SDK枚舉。(使字符串和枚舉的項一一對應)。它為程序提供了字符串來代表用戶選擇的一個特殊的操作,然后程序可以把這個字符串對應的值獲得並且把它傳送到使用的方法里面去。PIConstant集合包含了Members(不知道什么意思),存貯和訪問NamedValue對象。NamedValue對象是一個字符串(名字)-常量(數值)對。PIConstant集合中的對象通過PISDK.PIConstants.Item來獲取

       我覺得這個PIConstant集合就是相當於在C#中用DialogueResult枚舉中用OK代表某個具體的意思。具體代表的東西我們不用關心,知道是什么就可以了。NamedValue就是一個字符串-常量對,有點像一個字典吧,最后一句話說PISDK.PIConstants.Item來獲取PIContant,但是我在C#中PISDK.PIConstants沒有Item屬性,反而使直接通過PISDK.PIConstants[Name]取到。同時NamedValue是在PISDKCommon命名空間下面

       The PIPoint object represents a point on a PI Server. The PIPoint is the primary access point to data on the Server as well as configuration of a point's properties. 

       PIPoint對象表征PI數據庫里面的點,PIPoint是訪問數據庫里面點的值和屬性的主要方法。

       The PIData object is associated with a single PIPoint and is used to send and retrieve values to and from the server. It is accessed through the Data property of the PIPoint.

       PIData對象是和單獨的PIPoint聯系的,它從服務器獲取數據或者寫回數據到服務器。它通過PIPoint的Data屬性得到。

    我們知道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的,但是也可以大致了解得差不多。

 

2>應用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,問了一個比較有經驗的人,他說他沒有遇到過不能寫入的問題,等有時間去問問他,看看是不是版本的問題,如果有人能寫入的,請給我說一下你們的版本;

 

 

3>應用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類似吧。

 

程序員的基礎教程:菜鳥程序員


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM