Jazz Soft Contact us?   JazzSoft@live.com     English   English  Japanese  Chinese (Traditional)  Chinese (Simlified)
Factory Automation & Yield Management Solution Provider 
Skip Navigation LinksHome > Products > Savoy > Samples > GEM 300 (Visual Basic 2008)

Dorian.Core is added. Dorian now supports .NET 6 and 7.

Savoy ActiveX Control   




Brochures

Japanese

Savoy Sample - GEM 300 (Visual Basic 2008)

This sample will explain how to implement GEM 300 system with Savoy.




Constant Variables Definition

Define constant variable names using "Enum" expression. VIDs, CEIDs and ALID are used in this sample.
  1. VID

    Visual Basic

    Protected Enum VIDEnum
      VIDECTimer = 201
      VIDTimeFormat
      VIDControlState

      ' Load port state
      VIDLoadPortState1 = 301
      VIDLoadPortState2

      ' Access mode
      VIDAccessMode1 = 311
      VIDAccessMode2

      ' Slot map
      VIDSlotMap1 = 321
      VIDSlotMap2

      ' Carrier ID
      VIDCarrierID1 = 331
      VIDCarrierID2
    End Enum



  2. CEID

    Visual Basic

    Protected Enum CEIDEnum
      CEIDOffline = 51
      CEIDOnlineLocal
      CEIDOnlineRemote

      CEIDPJState = 60
      CEIDCJState = 70
      CEIDWaferProcessData = 80

      ' Carrier transfer request
      CEIDCarrierTransferRequest1 = 101
      CEIDCarrierTransferRequest2

      ' Load port transfer
      CEIDLoadPortTransfer1 = 111
      CEIDLoadPortTransfer2

      ' FOUP lock state
      CEIDFoupLockState1 = 121
      CEIDFoupLockState2

      ' Carrier transfer
      CEIDCarrierTransfer1 = 131
      CEIDCarrierTransfer2

      ' Carrier iD status
      CEIDCarrierIDStatus1 = 141
      CEIDCarrierIDStatus2

      ' Carrier location
      CEIDCarrierLocation1 = 151
      CEIDCarrierLocation2

      ' FOUP door state
      CEIDFoupDoorState1 = 161
      CEIDFoupDoorState2

      ' Carrier slot map state
      CEIDCarrierSlotMapState1 = 171
      CEIDCarrierSlotMapState2

      ' Access mode
      CEIDAccessMode1 = 181
      CEIDAccessMode2
    End Enum



  3. ALID

    Visual Basic

    Protected Enum ALIDEnum
      ALIDLoadWaferFailure = 1
    End Enum

Form Loading Process

  1. Retrieve Settings
    First, read bop data file and enable physical connection. There is a great feature to abbreviate object name using "With" in Visual Basic language.

    Visual Basic

    Private Sub MainForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      With gem
        .LoadData()
        .PhysicalConnection = True



  2. Enumerate Events
    Enumerate all events registered in bop data file. User can send any event by double-clicking on the list box. This feature is not always necessary when you make actual tool software.

    Visual Basic

        ' Enumerate all events
        Dim nCnt As Integer
        For nCnt = 0 To .CEIDCount - 1
          Dim lCEID As Long
          lCEID = .ToCEID(nCnt)

          Dim nIndex As Integer
          nIndex = eventlist.Items.Add(.get_CEIDDescription(lCEID))
        Next
      End With



  3. Enumerate Recipes
    Enumerate all recipes. When system receives S7F19, make recipe names list from this enumeration. When you make actual tool software, this sequence may be different such as referring data base or check recipe files. However, maintaining recipe list in the software memory simultaneously will prevent T3 timeout of S7F20 response. And also processing speed for S2F41 and S2F49 will become faster.

    Visual Basic

      With recipelist
        ' Dummy recipe list
        .Items.Add("Recipe1")
        .Items.Add("Recipe99")
        .Items.Add("RecipeABC")
        .Items.Add("RecipeXYZ")
      End With


  4. Objects Tree
    Display as tree style in order to intuitively understand the relationship among Carrier, CJ, PJ and Wafer objects. In this sample, 1 PJ will not be assigned on multiple carriers. However, the actual tool may have different paradigm. In addition, this kind of screen is not always necessary (but helpful for customers).

    Visual Basic

        With jobtree
          .Nodes.Add("Port1", gem.get_VIDValue(331))
          .Nodes.Add("Port2", gem.get_VIDValue(332))
        End With
      End Sub



Settings Dialog Box

Show setup dialog box from [Tools] - [Options...] menu. This sample specifies "-1" for the second argument in order to enable all tabs.

Visual Basic

  gem.Setup("", -1)



SavoyGem Events

SavoyGem notifies "Event" to user application in the event of situation change.
  1. Received Event
    Mostly DefProc() method processes messages, but it usually returns very plain reply messages. User has to process each message for GEM 300 extention.

    This sample processes important 4 messages; S3F17 (Proceed With Carrier), S7F19 (Query Recipe), S14F9 (Create CJ), S16F11 (Create PJ). For readability improvement purpose, put them into separate functions.

    Visual Basic

    Private Sub gem_Received(ByVal sender As System.Object, ByVal e As AxSAVOYLib._DSavoyGemEvents_ReceivedEvent) Handles gem.Received
      Debug.Print("Received(" + e.lpszIPAddress + ", " + Format$(e.lPortNumber) + ")")
      With gem
        If .ControlState = 4 Then
          If .Stream = 3 And .Function = 17 Then
            ' S3F17 Proceed with carrier
            ReceivedS3F17()
          End If

          If .Stream = 7 And .Function = 19 Then
            ' S7F19 Query recipe list
            SendS7F20()
          End If

          If .Stream = 14 And .Function = 9 Then
            ' S14F9 CJ create
            ReceivedS14F9()
          End If

          If .Stream = 16 And .Function = 11 Then
            ' S16F11 PJ create
            ReceivedS16F11()
          End If
        End If
        .DefProc()
      End With
    End Sub



  2. Other Events
    Display minimal information in debug window at this time.

    Visual Basic

      Debug.Print("Connected(" + e.lpszIPAddress + ", " + Format$(e.lPortNumber) + ")")




Message Processing

  1. Send S7F20
    When S7F19 arrived, call SendS7F20() function. Set reply message in the region of WorkSpace=0 and Reply=True. It is not necessary to change WorkSpace explicitly, because it will be set to 0 when Received event occurred.

    Visual Basic

      .Reply = True


    Since SavoyGem (and also SavoySecsII) will create child node unless otherwise root node was specified, chage Node property to root.

    Visual Basic

      .Node = ""


    Create SML text to be replied. Implemetation may vary depending on the recipe data storing method for actual tool. This sample will take recipe names from recipe list box.

    Visual Basic

      Dim strRecipe As String = "s7f20{"

      For Each item In recipelist.Items
        strRecipe += "<a'" + item + "'>"
      Next

      strRecipe += "}"
      .SML = strRecipe


    Once SML text string has been completed, set it to SML property. DefProc() method will send message after this function.


  2. Received S3F17
    This sample only processes ProceedWithCarrier, however, actual tool implementation will need additional features. It is recommended to support not only ProceedWithCarrier, but also CancelCarrier, CancelCarrierAtPort and other command for GEM 300. CarrierAction is embedded in Node="2" in S3F17.

    Visual Basic

      .Node = "2"
      Dim strCarrierAction As String = .NodeValue


    The reason why ToUpper() function was used for comparison is ignore cases.

    Visual Basic

      If strCarrierAction.ToUpper() <> "ProceedWithCarrier".ToUpper() Then
        ' Not supported
        Exit Sub
      End If


    It is needed to verify twice, one for carrier ID and one for slot map, for GEM 300. Some type of FOUP load port cannot read carrier ID other than undock position. It is common to dock and map wafer, when tool received carrier ID verification request in ProceedWithCarrier message.

    This sample generates mapping completion event as if it has done. Update associated slot map VID before sending event. There are 2 ways to update VID as follows:

    1. Specify string value directly by using VIDRawValue property
      Visual Basic

        .set_VIDValue(VIDEnum.VIDSlotMap1, "1111100000111110000011111")



    2. Specify SML string by using VIDValue property
      Visual Basic

        .set_VIDRawValue(VIDEnum.VIDSlotMap1, "<a'0000011111000001111100000'>")



    方法1では型に依存しない指定が可能です。 例えばVIDの型が以前はU2(符号なし16ビット整数)だったが、途中で仕様変更となりU4(符号なし32ビット整数)になった場合でもSMLを変更する必要がありません。 もし方法2でプログラミングしていた場合は、例えば<u2 345>ら<u4 345>に変更する必要があります。

    DVIDの場合は、方法1では指定できない場合があります。 VIDの型がリスト型の場合などがそれに該当します。 この場合は方法2を使って指定します。

    イベントを発生させるにはInvokeEvent()メソッドを使います。

    Visual Basic

      .InvokeEvent(CEIDEnum.CEIDCarrierSlotMapState1)



  3. Received S14F9
    パラメータは、属性IDと属性データのペアで送られてきます。 通常は装置の通信仕様書に書かれている通りの固定フォーマットですが、厳密にはSEMIの仕様では順序を入れ替えることも可能です。 もしホスト側でこのような順序変更を行っている場合は、装置の通信仕様書とは若干異なる順序でパラメータ指定がくる可能性があります。

    そこでまず属性IDと属性データのペアをすべて読み出し、いったんハッシュテーブルに保存することにします。 同様の解析処理はS2F41などでも使えます。 属性データがリスト構造の場合もありますから、すべての状況でこのテクニックが使える訳ではありませんので注意してください。

    Visual Basic

      Dim args As New Hashtable()
      .Node = "3"
      Dim nCnt As Integer
      Dim nNodeCount As Integer = .NodeCount
      For nCnt = 1 To nNodeCount
        ' Attribute ID
        .Node = "3/" + Format$(nCnt) + "/1"
        Dim strAttributeID As String = .NodeValue

        ' Attribute data
        .Node = "3/" + Format$(nCnt) + "/2"
        Dim strAttributeData As String = .NodeValue

        args.Add(strAttributeID, strAttributeData)
      Next


    CJIDをハッシュテーブルから「ControlJobID」に一致するデータを検索します。 見つからない場合(ホストから来なかった場合)には、Nothingとなります。 この値は後でチェックします。

    Visual Basic

      Dim strCJID As String = args("ControlJobID")


    キャリアIDはツリー構造になっている場合があります(装置がマルチキャリアCJに対応している場合)。 今回のサンプルでは直接読み出しています。

    Visual Basic

      .Node = "3/3/2/1"
      Dim strCarrierID As String = .NodeValue


    CJIDとキャリアIDが正しいかどうかをチェックします。 値がNothingかどうかで比べています。

    Visual Basic

      If strCJID Is Nothing Then
        SendS14F10(strCJID, strCarrierID, "", "{<u4 444><a'CJID was not specified'>}")
        Exit Sub
      End If


    Visual Basic

      If strCarrierID Is Nothing Then
        SendS14F10(strCJID, strCarrierID, "", "{<u4 555><a'Carrier ID was not specified'>}")
        Exit Sub
      End If


    CJIDが既に使われているかどうかをチェックします。 ここではリストに登録済みかどうかを調べていますが、実際の装置では実装が異なるかもしれません。

    Visual Basic

      For nCnt = 0 To joblist.Items.Count - 1
        If strCJID = joblist.Items(nCnt).SubItems(2).Text Then
          ' Error : Registered
          SendS14F10(strCJID, strCarrierID, "", "{<u4 666><a'CJID is in use'>}")
          Exit Sub
        End If
      Next


    ポート番号を調べます。 もしキャリアIDが一致しない場合はエラーとしています。 ただしマルチポートCJに対応した装置の場合には、このサンプルとは実装が異なりますので注意が必要です。

    Visual Basic

      Dim nPort As Integer
      If strCarrierID = .get_VIDValue(VIDEnum.VIDCarrierID1) Then
        ' Port 1
        nPort = 1
      Else
      If strCarrierID = .get_VIDValue(VIDEnum.VIDCarrierID2) Then
        ' Port 2
        nPort = 2
      Else
        ' Error : Carrier ID doesn't match
        SendS14F10(strCJID, strCarrierID, "", "{<u4 777><a'Carrier ID doesn' 0x27 't match'>}")
        Exit Sub
      End If
      End If


    CJに関連付けられたPJを移動します。 具体的にはCJの下にPJが配置されるようにツリーのノードを入れ替えます。

    Visual Basic

      .Node = "3/2/2"
      Dim strSlot As String = ""


    ツリーにはPort1またはPort2というキー名が関連付けられていますので、キャリアIDで文字列比較する必要はありません。

    Visual Basic

      Dim tree As TreeNode = jobtree.Nodes("Port" + Format$(nPort))


    ツリーノードの参照をジェネリックのリストクラスに登録していきます。 ジェネリックはC++のテンプレートと同じです。

    Visual Basic

      Dim listPJID As New List(Of TreeNode)
      nNodeCount = .NodeCount
      For nCnt = 0 To nNodeCount - 1


    CJに関連付けられたPJIDのノードを、CJの下に作成していきます。

    Visual Basic

      .Node = "3/2/2/" + Format$(nCnt + 1) + "/1"


    PJがツリーに登録されていない場合は、エラーとします。

    Visual Basic

      Dim treeFind As TreeNode = FindTreeItem(.NodeValue, tree)
      If treeFind Is Nothing Then
        SendS14F10(strCJID, strCarrierID, "", "{<u4 888><a'PJID doesn' 0x27 't match'>}")
        Exit Sub
      End If


    リストに登録します。

    Visual Basic

      listPJID.Add(treeFind)


    PJノードを移動します。 実際には移動ではなく、クローンを作成してオリジナルを消去します。 ツリーは子ノードを展開します。

    Visual Basic

      Dim treeCJ As TreeNode = tree.Nodes.Add(strCJID)
      For nCnt = 0 To listPJID.Count - 1


    ここでクローンを作成しています。

    Visual Basic

        Dim treePJ As TreeNode = listPJID(nCnt).Clone()
        treeCJ.Nodes.Add(treePJ)
        treePJ.Expand()


    同時にリストの3番目のカラム(CJID)を更新します。

    Visual Basic

        Dim lvi As ListViewItem = FindListItem(listPJID(nCnt).Text, 1, joblist)
        If lvi Is Nothing Then
        Else
          lvi.SubItems(2).Text = strCJID
        End If


    ツリーからオリジナルのPJノードを消去します。

    Visual Basic

        tree.Nodes.RemoveByKey(listPJID(nCnt).Text)
      Next
      treeCJ.Expand()


    正常完了した旨を返信します。 実際の装置では、生成されたオブジェクトの属性情報を返す必要があります。 オブジェクトをどう生成するかは、ソフトの実装によって異なります。

    Visual Basic

      SendS14F10(strCJID, strCarrierID, "<a'TODO : Set attributes'>", "")



  4. Send S14F10
    エラーのSMLノードが空の場合は、「エラーがない」という意味になります。 このため文字列が空かどうかをチェックします。

    Visual Basic

      Dim bAck As Boolean
      If strError = "" Then
        bAck = True
      Else
        bAck = False
      End If


    文字列をセットします。Boolean型をToString()すると「True」または「False」という文字列になりますので、このままSMLで利用することができます。

    Visual Basic

      .SML = "s16f12" & _
        "{" & _
        " <a'" & strCJID & "'>" & _
        " {" & _
        strAttribute & _
        " }" & _
        " {" & _
        " <bool " & bAck.ToString() & ">" & _
        " {" & _
        strError & _
        " }" & _
        " }" & _
        "}"



  5. Received S6F11
    メッセージからPJIDを取得します。

    Visual Basic

      .Node = "2"
      Dim strPJID As String = .NodeValue


    キャリアIDを取得します。

    Visual Basic

      .Node = "4/1/1"
      Dim strCarrierID As String = .NodeValue


    レシピ名を取得します。

    Visual Basic

      .Node = "5/2"
      Dim strRecipe As String = .NodeValue


    レシピ名が登録されているかを調べます。 実際の装置では、これがデータベースや、ファイルシステムとなる可能性があります。

    Visual Basic

      If Not IsValidRecipe(strRecipe) Then
        SendS16F12(strPJID, strCarrierID, "{<u4 111><a'Invalid recipe name'>}")
        Exit Sub
      End If


    PJIDが既に使用されていないかをチェックします。

    Visual Basic

      Dim nCnt As Integer
      For nCnt = 0 To joblist.Items.Count - 1
        If strPJID = joblist.Items(nCnt).SubItems(1).Text Then
          ' Error : Registered
          SendS16F12(strPJID, strCarrierID, "{<u4 222><a'PJID is in use'>}")
          Exit Sub
        End If
      Next


    スロット番号を取得します。 このサンプルでは省略しましたが、実際の装置では数値が1~25の範囲内にあるかどうかのチェックも必要です。 なおキャリアのスロット数は製品によって変わることがあるため、スロット番号を保持する変数には余裕を持たせておくほうがいいかもしれません。

    Visual Basic

      .Node = "4/1/2"
      Dim strSlot As String = ""
      Dim tree As TreeNode = jobtree.Nodes("Port" + Format$(nPort)).Nodes.Add(strPJID, strPJID)
      Dim nNodeCount As Integer = .NodeCount
      For nCnt = 0 To nNodeCount - 1
        .Node = "4/1/2/" + Format$(nCnt + 1)

        tree.Nodes.Add(.NodeValue, .NodeValue)

        If strSlot <> "" Then
          strSlot += ", "
        End If

        strSlot += .NodeValue
      Next
      tree.Expand()
      jobtree.Nodes("Port" + Format$(nPort)).Expand()


    受信したPJの情報をリストに登録します。 実際の装置では画面オブジェクトではなく、内部変数に登録するのがいいでしょう。

    Visual Basic

      Dim lvi As ListViewItem = joblist.Items.Add(strCarrierID)
      lvi.SubItems.Add(strPJID)
      lvi.SubItems.Add("")
      lvi.SubItems.Add(strRecipe)
      lvi.SubItems.Add(strSlot)


    PJが生成されたことをイベントで通知します。 実際の装置では関連するVID変数を更新する必要があります。

    Visual Basic

      SendS16F12(strPJID, strCarrierID, "")



  6. Send S16F12
    やはり追加情報がない場合は正常ということから、文字列が空かどうかをチェックして返信メッセージを作ります。

    Visual Basic

      .SML = "s16f12" & _
        "{" & _
        " " & _
        " {" & _
        " " & _
        " {" & _
        strInfo & _
        " }" & _
        " }" & _
        "}"



Searching Process

  1. Tree Search
    ツリーの指定されたノード以下から、対象となる文字列のノードを検索します。 ここではFor文を使用していますが、For Each文の方が若干処理が早くなるようです。

    Visual Basic

      Protected Function FindTreeItem(ByVal strFind As String, ByRef tree As TreeNode) As TreeNode
        FindTreeItem = Nothing
        Dim nCnt As Integer
        For nCnt = 0 To tree.Nodes.Count - 1
          If strFind = tree.Nodes(nCnt).Text Then
            FindTreeItem = tree.Nodes(nCnt)
            Exit Function
          End If
        Next
      End Function



  2. List Search
    リストの指定されたカラムに、その文字列があるか検索します。 このサンプルでは検索対象となるリストは1つだけなので、直接アクセスすれば引数3は不要です。

    Visual Basic

      Protected Function FindListItem(ByVal strFind As String, ByVal nColumn As Integer, ByRef list As ListView) As ListViewItem
        FindListItem = Nothing
        Dim nCnt As Integer
        For nCnt = 0 To list.Items.Count - 1
          If strFind = list.Items(nCnt).SubItems(nColumn).Text Then
            FindListItem = list.Items(nCnt)
            Exit Function
          End If
        Next
      End Function



  3. Query Recipe
    指定されたレシピが一覧に登録されているかチェックします。

    Visual Basic

      Protected Function IsValidRecipe(ByVal strRecipe) As Boolean
        IsValidRecipe = False
        Dim nCnt As Integer
        For nCnt = 0 To recipelist.Items.Count - 1
          If strRecipe = recipelist.Items(nCnt) Then
            IsValidRecipe = True
            Exit Function
          End If
        Next
      End Function



Event Tab

イベント一覧をダブルクリックすると、そのイベントをS6F11メッセージとして送信します。 ただしイベントが無効の場合は送信されません。

まずリストボックスで現在選択されている項目をチェックします。 何も選択されていないときは抜けます。

Visual Basic

  If eventlist.SelectedIndex < 0 Then
    Exit Sub
  End If


イベント一覧はCEIDのインデックスと同じ順序で並んでいますので、これをToCEID()メソッドを使ってCEID番号に変換します。 CEID番号を得たらInvokeEvent()メソッドでイベントを送信します。

レポートがリンクされている場合には、SavoyGemによってレポートが自動的に作られます。 このためInvokeEvent()メソッドを呼び出す直前に、関連するVID変数を更新する必要があります。 実際の装置を作成される場合には、膨大な数のVIDを更新する必要があるかもしれません。 さらにソフトの至る所でInvokeEvent()メソッドを呼び出すことになると思います。 その場合はVIDの更新処理を別関数にするのもいい方法です。

Visual Basic

  Dim lCEID As Long = .ToCEID(eventlist.SelectedIndex)
  .InvokeEvent(lCEID)



Data File

当初ソリューション(SavoySampleGem300VB.sln)には、データソースファイル(SavoySampleGem300VB.bopsource)をBopCompilerでコンパイルするための、カスタムビルドプロジェクト(BopDataFile.vcproj)が含まれていました。 このカスタムビルドプロジェクトはVisual C++プロジェクトをベースにしていたため、Visual Basic 2008 Express Editionではこのプロジェクトを開くことができませんでした。 この対策としてデータソースファイルのコンパイルをバッチファイル(MakeDataFile.bat)で行うように変更しました。

ソリューションのコンパイルが完了したら、binフォルダ下のDebugまたはReleaseフォルダ(ターゲットフォルダ)に実行ファイルが生成されます。 ビルドの際にバッチファイルとデータソースファイルは、ターゲットフォルダにコピーされるように設定されています。 SavoySampleGem300VB.exeを実行する前に、バッチファイルを実行するとBopCompilerが起動し、データファイル(SavoySampleGem300VB.bop)が生成されます。

ただしバッチファイルを実行するには、BopCompilerがインストールされているフォルダが環境変数Pathに含まれている必要があります。 ここでは環境変数への追加手順を説明します。
  1. 「Computer」(Windows XPでは「My Computer」)のアイコンを右クリックします。 ポップアップメニューから「Properties」をクリックします。




  2. 左のTasksペインに「Advanced system settings」という項目がありますので、これをクリックします。




  3. 「Advanced」タブの一番下に「Environment Variables」というボタンがありますので、これをクリックします。




  4. 環境変数のダイアログボックスが開きますので、下段の「System variables」の一覧から「Path」を選択し、「Edit」ボタンをクリックします。




  5. 「Variable value」の一番最後にセミコロン「;」を入力し、「C:\Program Files\Jazz Soft\Bop」フォルダを追加します。 入力が完了したらOKボタンをクリックします。



以上の手順で事前準備をしておくと、Explorerからバッチファイルをダブルクリックるだけで、データファイルが生成できるようになります。
Contact us?   JazzSoft@live.com
  Copyright © 1997 - 2024 Jazz Soft, Inc.