車両基地

車両基地のコントローラーを作ります。

・車両基地はループ区間を切り替えて作ります。列車がギャップを跨いだのを検知して車止め手前で停止させます。

 

 

【KiCadの回路図】

【基板】

レイアウト全体図

【PIC16F1827のコード】

//
//2021_0606
#include <xc.h>
#define _XTAL_FREQ 4000000
#define ADR 0x7C
#define RTC_ADR 0x64


#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
//#pragma config DEBUG = OFF
#pragma config FOSC =INTOSC //HS

#pragma config FCMEN = OFF
#pragma config MCLRE = OFF
#pragma config WDTE = OFF //ON
#pragma config CP = OFF
#pragma config LVP = OFF
#pragma config PWRTE = ON

#define ExtInt	RB0
#define ExtData	RB1


int IntCount;
unsigned char bit_p;
unsigned char receive_data;
unsigned char data_p;
unsigned char RxData[128];
unsigned char send_data;
unsigned char busy;
unsigned char p_counter;

unsigned char EnableBit[] = {1, 2, 4, 8, 16, 32, 64, 128};

unsigned char yard_req;
unsigned char yard_num;


//********************************************************

void main(void) {
    //最高速32MHz
    OSCCONbits.SPLLEN = 1; //×4 PLL
    OSCCONbits.IRCF = 14; //8MHz


    ANSELA = 0; // アナログ入力 AN8からAN13 を無効
    ANSELB = 0; // アナログ入力 AN0からAN7 を無効



    PORTA = 0;
    PORTB = 0;
    TRISA = 0x00; //All Input (FET OFF)
    TRISB = 0x03; // RB0,1 Input
    OPTION_REG = 0x0f; // WDT,Int Fall, pulup
    OPTION_REGbits.nWPUEN = 1;

    INTE = 1; // RB0 割り込み許可
    GIE = 1; // 割り込み許可

    __delay_ms(10); // 10msec



    while (1) {
        CLRWDT();
        if (yard_req & 0x80) { //リクエスト確認
            if (!busy) {
                busy = yard_req;
                yard_num = (yard_req & 0x70) >> 4; //yard番号

                switch (yard_num) {
                    case 0:
                        PORTA = yard_req & 0xf;
                        break;
                    case 1:
                        PORTB = (yard_req & 0xf) << 4;
                        break;
                }
            }
        } else {
            busy = 0; //busy off
        }
    }



}

void __interrupt() ISR_ExtInt(void) {
    //void interrupt ISR_ExtInt(void) {  
    unsigned char inp_bit;
    inp_bit = ExtData;

    INTF = 0; // 割り込みフラグクリア

    //RB4 = 1;

    IntCount++;

    if (ExtInt == 0) {
        //--- IntCount 0 ---
        IntCount = 0;
        if (p_counter)
            p_counter--;

    }


    //受信
    TRISB1 = 1; //PortInput

    data_p = (IntCount - 1) >> 3;
    bit_p = EnableBit[(IntCount - 1) & 0b111];

    if (inp_bit)
        receive_data |= bit_p;
    else
        receive_data &= ~bit_p;

    if (bit_p == 0x80) {
        RxData[data_p] = receive_data; //DataSet

        if (data_p == 0x61) {//0x61 yard
            yard_req = RxData[0x61]; //DataSet
        }
    }

    data_p = IntCount >> 3;

    if (data_p == 0x71) {//0x71 yard send
        //送信
        TRISB1 = 0; //PortOutput
        bit_p = EnableBit[IntCount & 0b111];

        send_data = busy;

        if (send_data & bit_p)
            ExtData = 1;
        else
            ExtData = 0;

    }


    //RB4 = 0;
}

【PIC32のソフト】

・PIC32のプロジェクトはSUBボードの製作で作ったプロジェクトのソースに統合しました。(2021_0606)

PC側ソフト

・YARDの番号と線番号を指定してYARDボタンを押すと指定のYardの線番号から発車します。

・走行中にYARDボタンを押すと指定したYARDの入り口に来たときに指定の線番号に入線して停車します。

・YARD2は、通過型で空いている線を通過できます。YARDを2に指定してボタンを押した時は停止位置で停車します。

VB Formのデザイン

UserControl ContPanelのデザイン

Form1のコード
Imports System.IO.Ports
Imports System.Runtime.Serialization.Formatters.Binary

Public Class Form1

    Const Tx_Byte As Integer = 128
    Const Rx_Byte As Integer = 230
    Const TxData数 As Integer = 12
    Const RxData数 As Integer = 12
    Private 列車数 As Integer = 3
    Const 最大列車数 As Integer = 8
    Public ポイント数 As Integer
    Const yard数 As Integer = 1
    Private TM(列車数) As Integer
    Private TM2 As Boolean
    Private 減速時スピード = 40


    Private PlayStep As Integer


    Private csv_writer As IO.StreamWriter

    Private Remcon As List(Of ContPanel) = New List(Of ContPanel)()

    Public Event yard_chg()


    Public Enum p処理 'ポイント処理定数
        なし
        ボタンON
        切替要求
        通過待ち
        切替中
    End Enum


    Public Enum y処理 'Yard処理定数
        なし
        Yard要求
        Yard発車要求
        Yard切替完了
        Yardポイント切替完了
        Yard停止
        Yard完全停止
        Yardポイント戻し完了
        Yard発車要求受付
        Yard発車準備完了
        Yard発車出口

        Yard終了
    End Enum


    <Serializable()> Class 位置情報
        Public 区間 As Integer
        Public 路線 As Integer
        Public 方向 As Integer
        Public 相 As Integer

        Sub New(ByVal 区 As Integer, ByVal 路 As Integer, ByVal 向 As Integer, ByVal sou As Integer)
            区間 = 区
            路線 = 路
            方向 = 向
            相 = sou
        End Sub

        Public ReadOnly Property Byte情報() As Byte
            Get
                Return 区間 + 路線 * 8 + 方向 * &H80 + 相 * &H40
            End Get

        End Property

        Sub 次区間()
            If 方向 = 0 Then
                区間 = (区間 + 1) And &H7
            Else
                区間 = (区間 - 1) And &H7
            End If
        End Sub
        Sub 前区間()
            If 方向 = 0 Then
                区間 = (区間 - 1) And &H7
            Else
                区間 = (区間 + 1) And &H7
            End If
        End Sub


        Function copy()
            Return New 位置情報(区間, 路線, 方向, 相)
        End Function

        Sub 逆転()
            If 方向 = 0 Then
                方向 = 1
            Else
                方向 = 0
            End If
        End Sub

        ' = 演算子をオーバーロード
        Public Shared Operator =(ByVal c1 As 位置情報, ByVal c2 As 位置情報) As Boolean
            If (c1.路線 = c2.路線) And (c1.区間 = c2.区間) And (c1.方向 = c2.方向) Then
                Return True
            Else
                Return False
            End If
        End Operator

        Public Shared Operator <>(ByVal c1 As 位置情報, ByVal c2 As 位置情報) As Boolean
            Return Not c1 = c2
        End Operator
    End Class

    Class train


        Public 現位置 As 位置情報
        Public 前位置 As 位置情報
        Public 次位置 As 位置情報
        Public 次々位置 As 位置情報

        Public 区間変化 As Boolean
        Public 安全 As Boolean
        Public speed As Single
        Public 逆転 As Integer

        Public 設定speed As Integer
        Public ポイント As Integer
        Public point処理状況 As p処理
        Public yard処理状況 As y処理
        Public ポイント番号 As Integer
        Public yard番号 As Integer
        Public 相変更FLAG As Boolean
        Public Power As Integer



        Public yard As Integer



        Sub New()
            'Dummyで登録(路線=7)
            現位置 = New 位置情報(0, 7, 0, 0)
            前位置 = 現位置.copy
            次位置 = 現位置.copy
            次々位置 = 現位置.copy
        End Sub


        Sub New(ByVal 現 As 位置情報)
            現位置 = 現
            前位置 = 現位置.copy
            前位置.前区間()
            次位置 = 現位置.copy
            次位置.次区間()
            次々位置 = 次位置.copy
            次々位置.次区間()

            区間変化 = True
        End Sub

        Sub New(ByVal 現 As 位置情報, ByVal 前 As 位置情報, ByVal 次 As 位置情報, ByVal 次々 As 位置情報)
            現位置 = 現
            前位置 = 前
            次位置 = 次
            次々位置 = 次々
        End Sub

        Sub 区間変更()
            前位置 = 現位置.copy
            現位置 = 次位置.copy
            次位置 = 次々位置.copy
            次々位置.次区間()

            区間変化 = True
        End Sub


        Sub 逆転処理()
            '現位置を前位置に、前位置を現位置に
            現位置.逆転()
            前位置.逆転()

            次位置 = 現位置.copy '前位置に入れるため
            現位置 = 前位置.copy
            前位置 = 次位置.copy

            次位置 = 現位置.copy
            次位置.次区間()
            次々位置 = 次位置.copy
            次々位置.次区間()
        End Sub

        Sub 相変更()

            If 現位置.相 = 0 Then
                現位置.相 = 1
                前位置.相 = 1
                次位置.相 = 1
                次々位置.相 = 1
            Else
                現位置.相 = 0
                前位置.相 = 0
                次位置.相 = 0
                次々位置.相 = 0
            End If


            相変更FLAG = True
            区間変化 = True

        End Sub


        Public ReadOnly Property Status As Byte
            Get
                Dim ret As Byte

                If 区間変化 Then ret = 1
                If Not 相変更FLAG Then
                    '相変更中は区間変更しない
                    If 安全 Then ret += &H80
                End If

                Return ret
            End Get
        End Property

        Public ReadOnly Property Enable As Boolean
            '列車運転中Enable
            Get
                If 現位置.路線 = 7 Then
                    Return False
                Else
                    Return True
                End If
            End Get
        End Property



    End Class

    Class PointClass
        Public 進入位置1 As 位置情報
        Public 進入位置2 As 位置情報
        'Public 出口位置1 As 位置情報
        'Public 出口位置2 As 位置情報

        Public 番号 As Integer




        Sub New(ByVal 位置1 As 位置情報, ByVal 位置2 As 位置情報, ByVal n As Integer)

            進入位置1 = 位置1
            進入位置2 = 位置2

            番号 = n
        End Sub

        Public ReadOnly Property 進入位置(ByVal 位置 As 位置情報) As 位置情報
            Get
                '進入位置なら対向進入位置を返す
                If (位置.路線 = 進入位置1.路線) And
                   (位置.区間 = 進入位置1.区間) And
                   (位置.方向 = 進入位置1.方向) Then

                    Dim ret As 位置情報 = 進入位置2.copy
                    ret.逆転()
                    ret.相 = 位置.相

                    Return ret
                End If

                If (位置.路線 = 進入位置2.路線) And
                   (位置.区間 = 進入位置2.区間) And
                   (位置.方向 = 進入位置2.方向) Then

                    Dim ret As 位置情報 = 進入位置1.copy
                    ret.逆転()
                    ret.相 = 位置.相

                    Return ret
                End If


                Return Nothing
            End Get
        End Property

        Public ReadOnly Property 出口位置(ByVal 現位置 As 位置情報) As Boolean
            Get
                '出口位置ならTRUEを返す
                Dim 位置 As 位置情報 = 現位置.copy

                位置.前区間()
                If 位置.方向 = 0 Then
                    If (位置.路線 = 進入位置2.路線) And (位置.区間 = 進入位置2.区間) Then
                        Return True
                    End If
                Else
                    If (位置.路線 = 進入位置1.路線) And (位置.区間 = 進入位置1.区間) Then
                        Return True
                    End If

                End If

                Return False

            End Get
        End Property

    End Class

    Class YardClass
        Public 発車位置 As 位置情報
        Public 進入位置 As 位置情報
        Public 停止位置 As 位置情報
        Public 出口位置 As 位置情報

        Public 停止位置1 As 位置情報
        Public 停止位置2 As 位置情報
        Public 出口位置1 As 位置情報
        Public 出口位置2 As 位置情報

        Public 進入位置2 As 位置情報
        Public 発車位置2 As 位置情報

        Public 分線 As Byte
        Public 列車 As Byte
        Public ポイント番号 As Integer
        Public type As Integer
        Public y制御Byte As Byte
        Public p制御Byte As Byte


        Sub New(ByVal 位置 As 位置情報, point As Integer, p As String, t As String, tp As Integer)
            分線 = Convert.ToInt32(p, 2)
            列車 = Convert.ToInt32(t, 2)
            発車位置 = 位置.copy '位置は発車位置
            進入位置 = 位置.copy
            停止位置 = 位置.copy
            出口位置 = 位置.copy

            進入位置.逆転() '進入位置は発車位置の逆転
            停止位置.逆転()
            停止位置.次区間() '停止位置は発車位置の逆の次区間
            出口位置.次区間() '出口位置は発車位置の次区間

            停止位置1 = 停止位置.copy
            出口位置1 = 出口位置.copy

            進入位置2 = 停止位置.copy
            進入位置2.逆転()
            発車位置2 = 停止位置.copy

            停止位置2 = 発車位置.copy
            出口位置2 = 発車位置2.copy
            出口位置2.次区間()

            ポイント番号 = point
            type = tp

        End Sub


        Public ReadOnly Property 空線 As Array
            Get

                Dim ret(7) As Integer
                Dim pos As Byte
                pos = Not (分線 And 列車) And 分線


                Dim c As Integer
                Dim num As Integer

                For n = 0 To 7
                    If (分線 And 2 ^ n) <> 0 Then
                        num += 1

                        If (pos And 2 ^ n) <> 0 Then
                            ret(c) = num
                            c += 1
                        End If
                    End If
                Next

                ReDim Preserve ret(c - 1)
                Array.Reverse(ret)
                Return ret
            End Get
        End Property

        Public ReadOnly Property 在線 As Array
            Get

                Dim ret(7) As Integer

                Dim c As Integer
                Dim num As Integer

                For n = 0 To 7
                    If (分線 And 2 ^ n) <> 0 Then
                        num += 1

                        If (列車 And 2 ^ n) <> 0 Then
                            ret(c) = num
                            c += 1
                        End If
                    End If
                Next

                ReDim Preserve ret(c - 1)
                Array.Reverse(ret)
                Return ret
            End Get
        End Property



        Function 番号位置変換(i As Integer)
            'bit 位置に変換
            Dim c As Integer

            For n = 0 To 7
                If (分線 And 2 ^ n) <> 0 Then
                    c += 1
                    If i = c Then
                        Return n
                    End If
                End If
            Next

            Return i
        End Function

        Public WriteOnly Property 列車Set(io As Boolean) As Integer
            Set(value As Integer)

                Dim pos = 番号位置変換(value)

                If io Then
                    '入線時
                    列車 = 列車 Or 2 ^ pos
                Else
                    '発車時
                    Dim p As Byte = Not 2 ^ pos And &HFF
                    列車 = 列車 And p
                End If
            End Set
        End Property



        Public ReadOnly Property 進入位置確認(位置 As 位置情報, pos As Integer) As Boolean
            Get
                Dim n = ポイント番号 - 3

                Dim p = 番号位置変換(pos)

                If type = 0 Then
                    y制御Byte = &H88 + n * &H10 + p
                    p制御Byte = &HC0 + ポイント番号
                    Return 位置 = 進入位置
                Else
                    If 位置 = 進入位置 Then
                        停止位置 = 停止位置1.copy
                        'y制御Byte = &H80 + n * &H10 + &H2 + p * 4
                        y制御Byte = &H80 + n * &H10 + &H1 + p * 2
                        p制御Byte = &H80 + p * &H40 + ポイント番号

                        Return True
                    ElseIf 位置 = 進入位置2 Then
                        '逆進入
                        停止位置 = 停止位置2.copy
                        'y制御Byte = &H80 + n * &H10 + p * 4
                        y制御Byte = &H80 + n * &H10 + p * 2
                        p制御Byte = &H80 + p * &H40 + ポイント番号

                        Return True
                    Else
                        Return False
                    End If
                End If
            End Get
        End Property

        Public Sub Yard終了処理()
            p制御Byte = p制御Byte Xor &H40

            If type = 0 Then
                y制御Byte = y制御Byte And &HF0
            Else
                '反対側の線に切り替え
                'y制御Byte = y制御Byte Xor &H4
                y制御Byte = y制御Byte Xor &H2
            End If

        End Sub

        Public Sub Yard発車処理(pos As Integer, d As Integer)
            Dim n = ポイント番号 - 3

            Dim p = 番号位置変換(pos)

            If type = 0 Then
                y制御Byte = &H88 + n * &H10 + p
                p制御Byte = &HC0 + ポイント番号
            Else
                y制御Byte = &H80 + n * &H10 + p * 2 '*4
                p制御Byte = &H80 + p * &H40 + ポイント番号

                If d = 1 Then
                    出口位置 = 出口位置2.copy
                Else
                    出口位置 = 出口位置1.copy
                End If
            End If


        End Sub

        Public Sub Yard発車終了処理()

            If type = 0 Then
                y制御Byte = y制御Byte And &HF0
                p制御Byte = p制御Byte Xor &H40
            Else
                If 列車 <> 3 Then
                    '0側空くときは0側へ切り替え
                    y制御Byte = y制御Byte And &HF8 '***
                    p制御Byte = p制御Byte And &HBF
                End If
            End If

        End Sub


    End Class

    Class 停止位置class
        Public 位置 As 位置情報
        Public ポイント番号 As Integer

        Sub New(p As 位置情報, n As Integer)
            位置 = p
            ポイント番号 = n
        End Sub
    End Class



    <Serializable()> Class Record

        Public 位置 As 位置情報
        Public ポイント番号 As Integer
        Public 逆転 As Boolean
        Public Yard番号 As Integer
        Public 線番号 As Integer
        Public 停止時間 As Integer
        Public スピード As Integer

        Sub New(ByRef tr As train)
            位置 = tr.現位置.copy
            ポイント番号 = -2
            Yard番号 = -1

            If tr.逆転 = 1 Then
                逆転 = True
            End If

        End Sub

    End Class
    <Serializable()> Class Rec_List

        Inherits List(Of Record)

        '最後の要素の逆転Set・Get 要素なしでFalse
        Public Property 逆転() As Boolean
            Get
                If Count > 0 Then
                    Return Last.逆転
                End If
                Return False
            End Get

            Set(value As Boolean)
                If Count > 0 Then
                    Last.逆転 = value
                End If
            End Set
        End Property

        Public Property ポイント() As Integer
            '最後の要素のポイント番号Set・Get 要素なしでFalse
            Get
                If Count > 0 Then
                    Return Last.逆転
                End If
                Return False
            End Get

            Set(value As Integer)
                If Count > 0 Then
                    Last.ポイント番号 = value
                End If
            End Set
        End Property

        Public Sub point_yard_set(ByRef tr As train)
            'Static Dim 切替中 As Boolean

            If Count > 0 Then
                'If Not 切替中 Then
                If tr.point処理状況 = p処理.切替中 Then
                    If Count > 1 Then
                        If Item(Count - 2).ポイント番号 <> tr.ポイント番号 Then
                            Last.ポイント番号 = tr.ポイント番号
                            '切替中 = True
                        End If
                    Else
                        Last.ポイント番号 = tr.ポイント番号
                    End If
                Else
                    Last.ポイント番号 = -2
                End If

                'Last.ポイント番号 = tr.point処理状況
                'Else
                '    If tr.point処理状況 = p処理.なし Then
                '        切替中 = False
                '    End If
                'End If


                If tr.yard処理状況 = y処理.Yardポイント切替完了 Then
                    Last.Yard番号 = tr.yard番号
                End If

                If Last.Yard番号 < 0 Then
                    Last.線番号 = 0
                End If

            End If

        End Sub

    End Class



    Public 列車(8) As train
    Public ポイント(4) As PointClass
    Public yard(1) As YardClass
    Public 車止位置(1) As 停止位置class


    Public 記録 As Rec_List = New Rec_List()


    'デリゲートの宣言
    Public Delegate Sub RsDelegate()

    'データーの受信
    Private Sub DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
        Handles SerialPort1.DataReceived

        'データの受信はマルチスレッドで行われる為にデリゲートを使用して
        'メインのスレッドでデータ処理の必要があります。
        Me.Invoke(New RsDelegate(AddressOf receive_data), New Object() {})
    End Sub


    '受信データー
    Public Sub receive_data()
        Dim byteArray(SerialPort1.BytesToRead - 1) As Byte

        Static GND_Level(9) As Integer
        Static c As Integer


        If byteArray.Length <> Rx_Byte Then
            Exit Sub
        End If


        'ポートのバッファから読み込み
        SerialPort1.Read(byteArray, 0, SerialPort1.BytesToRead)


        'ヘッダーチェック
        If (byteArray(0) <> &H55) Or (byteArray(1) <> &HAA) Then Exit Sub


        'Comm_data表示
        Dim data_txt As String = ""

        For n = 0 To 127
            Dim hex_str = "0" + Hex(byteArray(100 + n))
            data_txt += hex_str.Substring(hex_str.Length - 2, 2) + " "

            If n Mod 8 = 7 Then
                data_txt += vbCrLf
            End If
        Next

        Label3.Text = data_txt

        Dim 変化 As Byte = byteArray(4)


        For n = 0 To 列車数 - 1
            Dim pos As Integer = RxData数 * n
            Dim speed As Integer = 0
            Dim power As Integer = 0

            If 列車(n).Enable Then
                'スピードメータ-
                speed = byteArray(pos + 2) * 256 + byteArray(pos + 3)
                power = byteArray(pos + 7) * 256 + byteArray(pos + 8)
            End If

            Remcon(n).Speed_Meter = speed
            Remcon(n).Power_Meter = power

            'csv 出力
            'If n = 0 Then
            '    csv_writer.Write(speed.ToString + "," + power.ToString + ",")
            '    csv_writer.WriteLine(byteArray(pos + 4).ToString)
            'End If


            Dim 区間byte(3) As Byte
            区間byte(0) = 列車(n).現位置.Byte情報
            区間byte(1) = 列車(n).次位置.Byte情報

            Remcon(n).区間表示 = 区間byte

            列車(n).Power = power



            '区間変化の確認
            If byteArray(pos + 4) = &H80 Then
                If Not 列車(n).区間変化 Then
                    '立ち上がりのみ
                    列車(n).区間変更()
                    '全ての列車の情報更新
                    For m = 0 To 列車数 - 1
                        列車(n).区間変化 = True
                    Next
                    'c += 1
                    'Label2.Text = c

                    If 列車(n).point処理状況 = p処理.ボタンON Then
                        '区間頭でポイント切り替え要求
                        列車(n).point処理状況 = p処理.切替要求
                    End If

                End If
            Else
                '区間変化フラグクリア
                列車(n).区間変化 = False
            End If


            'Point_Clr
            If 列車(n).ポイント <> 0 Then
                If byteArray(pos + 5) = 列車(n).ポイント Then
                    列車(n).ポイント = 0 'point clr
                End If
            End If

            'yard_Clr
            If 列車(n).yard <> 0 Then
                If byteArray(pos + 6) = 列車(n).yard Then
                    列車(n).yard = 0 'yard clr
                End If
            End If

            '相変更FLAG CLR
            列車(n).相変更FLAG = False


        Next



        記録再生()

        '停止位置がポイントの時、ポイント切り替えON
        停止位置ポイント処理()


        'ポイント処理
        For n = 0 To 列車数 - 1
            Select Case 列車(n).point処理状況
                Case p処理.切替要求, p処理.通過待ち
                    'Point位置確認
                    For p As Integer = 0 To ポイント数 - 1
                        Dim 次位置 As 位置情報 = ポイント(p).進入位置(列車(n).現位置)
                        'ポイント番号確認
                        Select Case Remcon(n).point_num
                            Case -1, ポイント(p).番号 '-1は次のポイント
                                If Not 次位置 Is Nothing Then
                                    Select Case ポイント安全確認(n, 次位置)
                                        Case "安全"
                                            'ポイント切り替え
                                            列車(n).ポイント = &HC0 + ポイント(p).番号
                                            列車(n).次位置 = 次位置.copy
                                            次位置.次区間()
                                            列車(n).次々位置 = 次位置.copy
                                            列車(n).区間変化 = True

                                            列車(n).point処理状況 = p処理.切替中
                                            列車(n).ポイント番号 = p
                                            Remcon(n).CheckBox2.Enabled = False 'ポイントボタン不可
                                            Remcon(n).DomainUpDown1.Enabled = False
                                        Case "不可"

                                        Case "通過待ち"
                                            列車(n).point処理状況 = p処理.通過待ち
                                    End Select

                                    Exit For
                                End If
                        End Select
                    Next


                Case p処理.切替中
                    '出口位置確認
                    If ポイント(列車(n).ポイント番号).出口位置(列車(n).現位置) Then
                        'ポイント戻し
                        列車(n).ポイント = &H80 + ポイント(列車(n).ポイント番号).番号
                        列車(n).point処理状況 = p処理.なし
                        Remcon(n).CheckBox2.Enabled = True 'ポイントボタン可
                        Remcon(n).DomainUpDown1.Enabled = True 'ポイント選択可
                        Remcon(n).CheckBox2.Checked = False 'ポイントボタン戻し
                    End If

            End Select

            Yard処理(n)

        Next


        '安全確認
        For n = 0 To 列車数 - 1
            If 列車(n).Enable Then

                Select Case 安全確認(n)
                    Case "停止"
                        列車(n).安全 = False
                        列車(n).設定speed = 0
                        Remcon(n).信号 = "赤"
                    Case "減速"
                        Dim 減速速度 As Integer = 減速時スピード '減速時のスピード

                        列車(n).安全 = True
                        If Remcon(n).Speed_Cont > 減速速度 Then
                            列車(n).設定speed = 減速速度
                        Else
                            列車(n).設定speed = Remcon(n).Speed_Cont
                        End If
                        Remcon(n).信号 = "黄"
                    Case "安全"
                        Remcon(n).信号 = "緑"
                        列車(n).安全 = True

                        If 列車(n).逆転 = 1 Then
                            '逆転フラグが1なら逆転のため停止
                            列車(n).設定speed = 0
                        ElseIf 列車(n).point処理状況 = p処理.通過待ち Then
                            'ポイント通過待ちのため停止
                            列車(n).設定speed = 0
                        ElseIf 列車(n).yard処理状況 = y処理.Yard停止 Then
                            'Yardで停止
                            列車(n).設定speed = 0
                            Remcon(n).Speed_Cont = 0
                        Else
                            列車(n).設定speed = Remcon(n).Speed_Cont
                        End If

                    Case "向合停止"
                        列車(n).安全 = False
                        列車(n).設定speed = 0
                        Remcon(n).信号 = "赤"
                        Remcon(n).CheckBox1.Checked = True  '強制逆転

                End Select

            Else
                Remcon(n).信号 = "灰"
            End If
        Next


    End Sub

    Sub Yard処理(n As Integer)
        Select Case 列車(n).yard処理状況
            Case y処理.Yard要求
                Dim p = Remcon(n).NumericUpDown1.Value - 1
                If 列車(n).区間変化 Then
                    If yard(p).進入位置確認(列車(n).現位置, Val(Remcon(n).DomainUpDown2.Text)) Then
                        'yard切り替え
                        列車(n).yard = yard(p).y制御Byte
                        列車(n).yard処理状況 = y処理.Yard切替完了
                        列車(n).yard番号 = p
                        Remcon(n).Yard_Cont = False 'yard cont desable
                    End If
                End If

            Case y処理.Yard切替完了
                'ポイント切り替え
                If 列車(n).yard = 0 Then 'yard 切り替え確認
                    列車(n).ポイント = yard(列車(n).yard番号).p制御Byte
                    列車(n).yard処理状況 = y処理.Yardポイント切替完了

                End If


            Case y処理.Yardポイント切替完了
                If 列車(n).現位置 = yard(列車(n).yard番号).停止位置 Then
                    'yard停止
                    列車(n).yard処理状況 = y処理.Yard停止
                End If

            Case y処理.Yard完全停止
                'Yardポイント戻し
                yard(列車(n).yard番号).Yard終了処理()

                列車(n).ポイント = yard(列車(n).yard番号).p制御Byte

                列車(n).yard処理状況 = y処理.Yardポイント戻し完了
                'Timer2.Interval = 1000
                'Timer2.Enabled = True 'ポイント切り替え待ち
                TM(n) = 10

            Case y処理.Yardポイント戻し完了
                If TM(n) = 0 Then
                    'TM(n) = False
                    'yard戻し
                    列車(n).yard = yard(列車(n).yard番号).y制御Byte
                    列車(n).yard処理状況 = y処理.Yard終了
                End If

            Case y処理.Yard終了
                If 列車(n).yard = 0 Then 'yard 切り替え確認
                    yard(列車(n).yard番号).列車Set(True) = Val(Remcon(n).DomainUpDown2.Text)

                    列車(n) = New train() '列車Disable
                    Remcon(n).Yard_Cont = True 'yard cont enable
                    RaiseEvent yard_chg()

                End If

            Case y処理.Yard発車要求
                Dim p = Remcon(n).NumericUpDown1.Value - 1

                'yard切り替え
                If yard(p).type = 1 Then
                    If Remcon(n).CheckBox4.Checked Then '発車方向
                        列車(n) = New train(yard(p).発車位置2)
                    Else
                        列車(n) = New train(yard(p).発車位置)
                    End If
                Else
                    列車(n) = New train(yard(p).発車位置)
                End If

                If Yard安全確認(n) Then
                    If Remcon(n).CheckBox4.Checked Then
                        '逆転戻し
                        Remcon(n).CheckBox4.Checked = False
                    End If

                    yard(p).Yard発車処理(Val(Remcon(n).DomainUpDown2.Text), 列車(n).現位置.方向)

                    列車(n).yard = yard(p).y制御Byte
                    列車(n).yard処理状況 = y処理.Yard発車要求受付
                    列車(n).yard番号 = p
                    Remcon(n).Yard_Cont = False 'yard cont desable
                Else
                    列車(n) = New train() '列車Disable
                    列車(n).yard処理状況 = y処理.Yard発車要求
                End If



            Case y処理.Yard発車要求受付
                'ポイント切り替え
                If 列車(n).yard = 0 Then 'yard 切り替え確認
                    列車(n).ポイント = yard(列車(n).yard番号).p制御Byte
                    列車(n).yard処理状況 = y処理.Yard発車準備完了
                End If

            Case y処理.Yard発車準備完了
                If 列車(n).現位置 = yard(列車(n).yard番号).出口位置 Then
                    If 列車(n).ポイント = 0 Then
                        'Yardポイント戻し
                        yard(列車(n).yard番号).Yard発車終了処理()
                        列車(n).ポイント = yard(列車(n).yard番号).p制御Byte
                        列車(n).yard処理状況 = y処理.Yard発車出口
                        'Timer2.Interval = 1000
                        'Timer2.Enabled = True 'ポイント切り替え待ち
                        TM(n) = 10
                    End If
                End If

            Case y処理.Yard発車出口
                If TM(n) = 0 Then
                    'TM(n) = False
                    'yard戻し
                    列車(n).yard = yard(列車(n).yard番号).y制御Byte
                    yard(列車(n).yard番号).列車Set(False) = Val(Remcon(n).DomainUpDown2.Text)

                    列車(n).yard処理状況 = y処理.なし
                    Remcon(n).Yard_Cont = True
                    RaiseEvent yard_chg()

                End If

        End Select


    End Sub

    Sub 停止位置ポイント処理()
        '停止位置がポイントの時、ポイント切り替えON

        For n = 0 To 列車数 - 1
            If 列車(n).point処理状況 = p処理.なし Then
                For Each p As 停止位置class In 車止位置
                    If 列車(n).現位置 = p.位置 Then
                        If p.ポイント番号 >= 0 Then
                            'ポイント切り替えON
                            Remcon(n).DomainUpDown2.Text = p.ポイント番号
                            'Remcon(n).CheckBox2.Checked = True
                            列車(n).point処理状況 = p処理.切替要求
                        End If
                    End If
                Next
            End If
        Next

    End Sub


    Function 安全確認(ByVal n As Integer) As String

        Dim 停止 As Boolean = False
        Dim 減速 As Boolean = False
        Dim 向合停止 As Boolean = False


        For m As Integer = 0 To 列車数 - 1
            If m <> n Then
                '次位置が他の列車の現、前、次位置と同じなら停止
                If (列車(n).次位置.路線 = 列車(m).現位置.路線) And
                   (列車(n).次位置.区間 = 列車(m).現位置.区間) Then 停止 = True

                If (列車(n).次位置.路線 = 列車(m).前位置.路線) And
                   (列車(n).次位置.区間 = 列車(m).前位置.区間) Then 停止 = True

                If 列車(n).point処理状況 = p処理.切替中 Then
                    'ポイント切り替え中
                    If 列車(n).現位置.方向 <> 列車(m).現位置.方向 Then
                        If (列車(n).次位置.路線 = 列車(m).次位置.路線) And
                        (列車(n).次位置.区間 = 列車(m).次位置.区間) Then 停止 = True
                    End If
                Else
                    If (列車(n).次位置.路線 = 列車(m).次位置.路線) And
                   (列車(n).次位置.区間 = 列車(m).次位置.区間) Then 停止 = True
                End If


                '次々位置が他の列車の現、前、次位置と同じなら減速
                If (列車(n).次々位置.路線 = 列車(m).現位置.路線) And
                   (列車(n).次々位置.区間 = 列車(m).現位置.区間) Then 減速 = True

                If (列車(n).次々位置.路線 = 列車(m).前位置.路線) And
                   (列車(n).次々位置.区間 = 列車(m).前位置.区間) Then 減速 = True

                If (列車(n).次々位置.路線 = 列車(m).次位置.路線) And
                   (列車(n).次々位置.区間 = 列車(m).次位置.区間) Then 減速 = True

                If 停止 Then
                    If (n > m) And (列車(n).現位置.方向 <> 列車(m).現位置.方向) Then
                        向合停止 = True '方向逆で優先順位低いとき
                        Return "向合停止"
                    End If
                    Exit For
                End If


            End If

        Next


        For Each p As 停止位置class In 車止位置
            If p.ポイント番号 < 0 Then
                'ポイントのない停止位置
                If 列車(n).現位置 = p.位置 Then
                    '現位置なら停止
                    停止 = True
                    Exit For
                ElseIf 列車(n).次位置 = p.位置 Then
                    '次位置なら減速
                    減速 = True
                    Exit For
                End If
            End If
        Next




        '通過形ヤードで空き線なしは通過不可
        For Each p As YardClass In yard
            If p.type = 1 Then
                '通過形ヤードの時
                If p.空線.Length = 0 Then
                    '空線なしの時
                    If (列車(n).現位置 = p.進入位置) Or (列車(n).現位置 = p.進入位置2) Then
                        停止 = True
                        Exit For
                    End If
                End If
            End If
        Next


        'Yard減速
        If 列車(n).yard処理状況 = y処理.Yardポイント切替完了 Then
            減速 = True
        End If


        If 停止 Then Return "停止"
        If 減速 Then Return "減速"

        Return "安全"

    End Function

    Function ポイント安全確認(ByVal n As Integer, ByVal 位置 As 位置情報) As String

        Dim 相手路線列車数 As Integer
        Dim 相手 As Integer
        Dim 停止 As Boolean

        For m As Integer = 0 To 列車数 - 1
            If m <> n Then
                '位置が他の列車の現、前、次位置と同じなら非安全
                If (位置.路線 = 列車(m).現位置.路線) And
                   (位置.区間 = 列車(m).現位置.区間) Then 停止 = True

                If (位置.路線 = 列車(m).前位置.路線) And
                   (位置.区間 = 列車(m).前位置.区間) Then 停止 = True

                If (位置.路線 = 列車(m).次位置.路線) And
                   (位置.区間 = 列車(m).次位置.区間) Then 停止 = True

                If (位置.路線 = 列車(m).次々位置.路線) And
                   (位置.区間 = 列車(m).次々位置.区間) Then 停止 = True


                '相手路線の列車数確認
                If 位置.路線 = 列車(m).現位置.路線 Then
                    相手路線列車数 += 1
                    相手 = m
                End If


            End If
        Next

        '路線に列車が2台いるときはポイント切り替え不可
        If 相手路線列車数 >= 2 Then Return "不可"

        If 停止 Then Return "通過待ち"

        '列車が1台いるときは相手の相を確認
        If 相手路線列車数 = 1 Then
            '相が同じなら相手の相を変更
            If 列車(相手).現位置.相 = 列車(n).現位置.相 Then 列車(相手).相変更()
        End If


        Return "安全"

    End Function


    Function Yard安全確認(ByVal n As Integer) As Boolean

        Dim 相手路線列車数 As Integer
        Dim 相手 As Integer
        Dim 停止 As Boolean

        For m As Integer = 0 To 列車数 - 1
            If m <> n Then

                '現位置が他の列車の現、前、次位置、次々位置と同じなら停止
                If (列車(n).現位置.路線 = 列車(m).現位置.路線) And
                   (列車(n).現位置.区間 = 列車(m).現位置.区間) Then 停止 = True

                If (列車(n).現位置.路線 = 列車(m).前位置.路線) And
                   (列車(n).現位置.区間 = 列車(m).前位置.区間) Then 停止 = True

                If (列車(n).現位置.路線 = 列車(m).次位置.路線) And
                   (列車(n).現位置.区間 = 列車(m).次位置.区間) Then 停止 = True

                If (列車(n).現位置.路線 = 列車(m).次々位置.路線) And
                   (列車(n).現位置.区間 = 列車(m).次々位置.区間) Then 停止 = True


                '前位置が他の列車の現、前、次位置、次々位置と同じなら停止
                If (列車(n).前位置.路線 = 列車(m).現位置.路線) And
                   (列車(n).前位置.区間 = 列車(m).現位置.区間) Then 停止 = True

                If (列車(n).前位置.路線 = 列車(m).前位置.路線) And
                   (列車(n).前位置.区間 = 列車(m).前位置.区間) Then 停止 = True

                If (列車(n).前位置.路線 = 列車(m).次位置.路線) And
                   (列車(n).前位置.区間 = 列車(m).次位置.区間) Then 停止 = True

                If (列車(n).前位置.路線 = 列車(m).次々位置.路線) And
                   (列車(n).前位置.区間 = 列車(m).次々位置.区間) Then 停止 = True



                '相手路線の列車数確認
                If 列車(n).現位置.路線 = 列車(m).現位置.路線 Then
                    相手路線列車数 += 1
                    相手 = m
                End If


            End If
        Next

        '路線に列車が2台いるときはポイント切り替え不可
        If 相手路線列車数 >= 2 Then Return False

        If 停止 Then Return False

        '列車が1台いるときは相手の相を確認
        If 相手路線列車数 = 1 Then
            '相が同じなら相を変更
            If 列車(相手).現位置.相 = 列車(n).現位置.相 Then 列車(n).相変更()
        End If


        Return True

    End Function


    Private Sub 記録再生()
        Static Dim 変化 As Boolean

        If 列車(0).区間変化 And Not 変化 Then
            変化 = True
            '区間変更時
            If Remcon(0).CheckBox5.Checked Then
                '列車0の記録
                If 記録.逆転 And (列車(0).逆転 = 1) Then
                    '逆転後区間変更のとき1つ前の逆転はFalse
                    記録.逆転 = False

                    DomainUpDown1.Items(DomainUpDown1.Items.Count - 1) = 記録msg(記録.Last, 記録.Count)
                End If

                '一時停止後は次区間のスピードをセット
                If 記録.Last.スピード = -1 Then
                    記録.Last.スピード = Remcon(0).Speed_Cont
                End If

                記録.Last.線番号 = Remcon(0).線番号
                記録.point_yard_set(列車(0))

                記録.Add(New Record(列車(0)))
                記録.Last.スピード = Remcon(0).Speed_Cont

                DomainUpDown1.Items.Add(記録msg(記録.Last, 記録.Count))
                DomainUpDown1.SelectedIndex = DomainUpDown1.Items.Count - 1

            End If

            If Remcon(0).CheckBox6.Checked Then
                '列車0のPlay
                If 記録(PlayStep).位置 = 列車(0).現位置 Then
                    Remcon(0).Speed_Cont = 記録(PlayStep).スピード

                    '逆転
                    If 記録(PlayStep).逆転 Then
                        列車(0).逆転 = 1
                    End If
                    'ポイント切り替え
                    If 記録(PlayStep).ポイント番号 > -2 Then
                        列車(0).point処理状況 = p処理.切替要求
                        Remcon(0).point_num = ポイント(記録(PlayStep).ポイント番号).番号
                    End If
                    'Yard切り替え
                    If 記録(PlayStep).Yard番号 > -1 Then
                        列車(0).yard処理状況 = y処理.Yard要求
                        Remcon(0).NumericUpDown1.Value = 記録(PlayStep).Yard番号 + 1
                        Remcon(0).線番号 = 記録(PlayStep).線番号

                    End If



                    '停止時間ありでstep中止
                    If 記録(PlayStep).停止時間 = 0 Then
                        PlayStep += 1
                    End If


                    If 記録.Count <= PlayStep Then
                        'Play終了
                        Remcon(0).CheckBox6.Checked = False
                        Remcon(0).Speed_Cont = 0
                        PlayStep = 0
                    Else
                        Label2.Text = PlayStep
                        DomainUpDown1.SelectedIndex = PlayStep
                    End If
                End If
            End If


        Else
            変化 = False
        End If


        If Remcon(0).CheckBox5.Checked Then
            'Yard発車記録
            If 列車(0).yard処理状況 = y処理.Yard発車要求受付 Then
                記録.Add(New Record(列車(0)))
                記録.Last.Yard番号 = 列車(0).yard番号
                記録.Last.線番号 = Remcon(0).線番号

                記録.Last.スピード = Remcon(0).Speed_Cont
                'Dim mes As String = String.Format("{0} 路線{1} 区間{2} 逆転{3} ポイント{4} Yard{5}", 記録.Count, 記録.Last.位置.路線, 記録.Last.位置.区間, 記録.Last.逆転, 記録.Last.ポイント番号, 記録.Last.Yard番号)
                'DomainUpDown1.Items.Add(mes)
                DomainUpDown1.Items.Add(記録msg(記録.Last, 記録.Count))

            End If

            'Yard停車記録
            If 列車(0).yard処理状況 = y処理.Yard終了 Then
                記録.Last.停止時間 = 5
            End If

            '停止の記録 走行中スピード0
            If 列車(0).Enable Then
                If 列車(0).yard処理状況 = y処理.なし Then
                    If Remcon(0).Speed_Cont = 0 Then
                        If 列車(0).Power = 0 Then
                            If 記録.Last.スピード <> -1 Then
                                記録.Last.スピード = 0
                                記録.Last.停止時間 = 5
                                記録.Add(New Record(列車(0)))
                                記録.Last.スピード = -1
                            End If
                        End If
                    End If
                End If
            End If


        End If


        If Remcon(0).CheckBox6.Checked Then
            'Yard発車PLAY
            If 列車(0).Enable = False Then
                'Yard切り替え
                If 記録(PlayStep).Yard番号 > -1 Then
                    列車(0).yard処理状況 = y処理.Yard発車要求
                    Remcon(0).NumericUpDown1.Value = 記録(PlayStep).Yard番号 + 1
                    Remcon(0).線番号 = 記録(PlayStep).線番号

                    Remcon(0).Speed_Cont = 記録(PlayStep).スピード

                    PlayStep += 1
                    Label2.Text = PlayStep
                    DomainUpDown1.SelectedIndex = PlayStep
                    TM2 = False
                End If
            End If

            '停止タイマーON
            If 列車(0).yard処理状況 = y処理.Yard終了 Then
                If 記録(PlayStep).停止時間 > 0 Then
                    Timer2.Interval = 記録(PlayStep).停止時間 * 1000
                    Timer2.Enabled = True
                    Label4.Text = "TimerON"

                End If
            End If

            '一時停止時
            If 列車(0).Enable And Not Timer2.Enabled Then
                If Remcon(0).Speed_Cont = 0 Then
                    If 列車(0).Power = 0 Then
                        If 記録(PlayStep).停止時間 > 0 Then
                            Timer2.Interval = 記録(PlayStep).停止時間 * 1000
                            Timer2.Enabled = True
                            Label4.Text = "TimerON"
                        End If
                    End If
                End If
            End If

            '一時停止からの起動
            If TM2 Then
                Remcon(0).Speed_Cont = 記録(PlayStep).スピード
                PlayStep += 1
                Label2.Text = PlayStep
                DomainUpDown1.SelectedIndex = PlayStep
                TM2 = False
            End If

        End If


    End Sub

    Function 記録msg(ByRef rec As Record, c As Integer) As String
        Dim rev As String = "OFF"
        If rec.逆転 Then rev = "ON"
        Dim point As String = rec.ポイント番号
        If rec.ポイント番号 = -2 Then point = "OFF"
        Dim yard As String = rec.Yard番号 + 1
        If rec.Yard番号 = -1 Then yard = "OFF"

        Dim ret As String = String.Format("{0} 路線{1} 区間{2} 逆転{3} ポイント{4} Yard{5} 線番号{6} 停止時間{7} Speed{8}",
                            c, rec.位置.路線, rec.位置.区間, rev, point, yard, rec.線番号, rec.停止時間, rec.スピード)

        Return ret
    End Function


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'ポート接続処理
        SerialPort1.PortName = ComboBox1.Text

        SerialPort1.BaudRate = 115200
        'SerialPort1.BaudRate = 9600
        SerialPort1.Parity = IO.Ports.Parity.None
        SerialPort1.DataBits = 8
        SerialPort1.StopBits = IO.Ports.StopBits.One

        SerialPort1.ReceivedBytesThreshold = Rx_Byte

        SerialPort1.ReadTimeout = 500
        SerialPort1.WriteTimeout = 500

        SerialPort1.Open()

        Timer1.Enabled = True

        Button1.Enabled = False
        Button2.Enabled = True
        ComboBox1.Enabled = False

    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'ポート切断処理
        Timer1.Enabled = False
        SerialPort1.Close()
        ComboBox1.Enabled = True
        Button1.Enabled = True
        Button2.Enabled = False
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim Txdata(Tx_Byte) As Byte
        Dim 加速 As Single = 0.3


        'ヘッダーとして&H55,&HAAを送る
        Txdata(0) = &H55
        Txdata(1) = &HAA



        For n = 0 To 列車数 - 1
            If 列車(n).Enable Then

                'speed 加速・減速
                If 列車(n).設定speed - 列車(n).speed < 0 Then
                    If 列車(n).yard処理状況 = y処理.Yard停止 Then
                        加速 = 1
                    Else
                        加速 = 0.5
                    End If
                End If



                列車(n).speed += (列車(n).設定speed - 列車(n).speed) * 加速

                '逆転フラグ確認
                If 列車(n).逆転 = 1 Then
                    If Int(列車(n).speed) = 0 Then
                        If 列車(n).Power = 0 Then
                            '列車が停止したら逆転
                            列車(n).逆転処理()
                            列車(n).逆転 = 0
                            列車(n).区間変化 = True  '位置情報更新の為


                            '逆転ボタン戻し
                            Remcon(n).CheckBox1.Checked = False
                            Remcon(n).CheckBox1.Enabled = True
                        End If
                    End If
                End If

                'Yardでの停止確認
                If 列車(n).yard処理状況 = y処理.Yard停止 Then
                    If Int(列車(n).speed) = 0 Then
                        If 列車(n).Power = 0 Then
                            列車(n).yard処理状況 = y処理.Yard完全停止
                        End If
                    End If
                End If


            End If
        Next


        For n = 0 To 最大列車数 - 1
            Dim p As Integer = n * TxData数 + 2
            Txdata(p) = Int(列車(n).speed) 'speed data
            Txdata(p + 1) = 列車(n).現位置.Byte情報
            Txdata(p + 2) = 列車(n).前位置.Byte情報
            Txdata(p + 3) = 列車(n).次位置.Byte情報
            Txdata(p + 4) = 列車(n).Status
            Txdata(p + 5) = 列車(n).ポイント
            Txdata(p + 6) = 列車(n).yard

        Next



        Try
            SerialPort1.Write(Txdata, 0, Tx_Byte) 'データ送信

        Catch ex As Exception
            'エラーのとき
            Button2_Click(Nothing, Nothing) '切断
            MsgBox(ex.Message)
        End Try

        'YARD用タイマー
        For n = 0 To 列車数 - 1
            If TM(n) > 0 Then
                TM(n) -= 1
            End If
        Next



    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim ports As String() = SerialPort.GetPortNames()

        If ports.Count = 0 Then
            MsgBox("シリアルポートが見つかりません。")
            Button1.Enabled = False
        Else
            '使用可能なシリアルポートをコンボボックスに登録
            ComboBox1.Items.AddRange(ports)
            ComboBox1.SelectedIndex = 0
        End If

        'ComboBox1.SelectedIndex = 2
        ComboBox1.Text = "COM11"

        Me.Text = "PC Remote"
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.Fixed3D
        Me.MinimizeBox = False
        Me.MaximizeBox = False

        Button1.Text = "接続"
        Button2.Text = "切断"
        Button3.Text = "切替"
        Button4.Text = "戻し"
        Button5.Text = "開く"
        Button6.Text = "保存"


        GroupBox1.Text = ""
        GroupBox2.Text = "ポイントテスト"
        GroupBox3.Text = "プログラム運転"

        CheckBox1.Text = "メモリ表示"
        CheckBox1.Checked = True
        CheckBox1.Appearance = Appearance.Button
        CheckBox2.Text = "Repeat"


        DomainUpDown1.Text = ""
        Label1.Text = ""
        Label2.Text = ""
        Label3.Text = ""
        Label4.Text = ""


        Button2.Enabled = False '切断ボタンdisable



        Timer1.Interval = 200 'タイマーインターバル200ms


        'Dummy Data
        For n = 0 To 最大列車数 - 1
            列車(n) = New train()
        Next

        '列車情報設定 
        '列車(0) = New train(New 位置情報(1, 0, 0, 0))

        '列車(1) = New train(New 位置情報(4, 0, 0, 1))

        '列車(2) = New train(New 位置情報(1, 1, 0, 0))

        'ポイント情報設定
        'ポイント(0) = New PointClass(New 位置情報(4, 0, 0, 0), New 位置情報(5, 1, 1, 0), 0)
        'ポイント(1) = New PointClass(New 位置情報(4, 1, 0, 0), New 位置情報(5, 0, 1, 0), 0)

        ポイント(0) = New PointClass(New 位置情報(1, 0, 0, 0), New 位置情報(3, 1, 1, 0), 0)
        ポイント(1) = New PointClass(New 位置情報(2, 1, 0, 0), New 位置情報(2, 0, 1, 0), 0)
        ポイント(2) = New PointClass(New 位置情報(0, 1, 0, 0), New 位置情報(0, 2, 1, 0), 1)
        ポイント(3) = New PointClass(New 位置情報(3, 2, 0, 0), New 位置情報(7, 0, 1, 0), 2)

        ポイント数 = 4


        yard(0) = New YardClass(New 位置情報(7, 1, 1, 0), 3, "11010101", "01010001", 0)
        yard(1) = New YardClass(New 位置情報(0, 0, 0, 0), 4, "11", "01", 1)

        '行き止まり位置
        車止位置(0) = New 停止位置class(New 位置情報(0, 2, 1, 0), 1)
        車止位置(1) = New 停止位置class(New 位置情報(3, 2, 0, 0), 2)



        For n As Integer = 0 To 列車数 - 1
            Remcon.Add(New ContPanel(n))
            Remcon(n).Top = 10
            Remcon(n).Left = Remcon(0).Width * n + 2
            Controls.Add(Remcon(n))

            AddHandler Remcon(n).逆転_Click, AddressOf 逆転_Click
            AddHandler Remcon(n).ポイント_Click, AddressOf ポイント_Click
            AddHandler Remcon(n).Yard_Click, AddressOf Yard_Click

            Remcon(n).add_point(ポイント) 'リモコンにポイント番号登録
        Next

        'rec_click
        AddHandler Remcon(0).Rec_Click, AddressOf Rec_Click

        Me.Height = Remcon(0).Height + GroupBox3.Height + 70
        GroupBox1.Left = Remcon(0).Width * 列車数 + 20
        Label3.Left = GroupBox1.Left + GroupBox1.Width + 20
        Me.Width = Label3.Left + Label3.Width + 40

        GroupBox3.Top = Remcon(0).Height + 20

        'Log用
        csv_writer = New IO.StreamWriter("out.csv", False, System.Text.Encoding.GetEncoding("Shift_JIS"))


    End Sub

    Private Sub 逆転_Click(ByVal index As Integer)
        '逆転ボタン確認
        If Remcon(index).CheckBox1.Checked Then
            '列車逆転のため停止させる
            列車(index).逆転 = 1
            Remcon(index).CheckBox1.Enabled = False
        End If

    End Sub

    Private Sub ポイント_Click(ByVal index As Integer)
        'ポイントボタン確認
        If Remcon(index).CheckBox2.Checked Then
            'ポイント切り替え要求
            '列車(index).point処理状況 = p処理.切替要求
            列車(index).point処理状況 = p処理.ボタンON
            列車(index).ポイント番号 = Remcon(index).point_num
        Else
            列車(index).point処理状況 = p処理.なし
        End If

    End Sub

    Private Sub Yard_Click(ByVal index As Integer)
        'Yardボタン確認
        Dim y As y処理

        If 列車(index).Enable Then
            y = y処理.Yard要求
        Else
            y = y処理.Yard発車要求
        End If

        If Remcon(index).CheckBox3.Checked Then
            'Yard要求
            列車(index).yard処理状況 = y
        End If

    End Sub

    Private Sub Rec_Click()
        'Rec開始時記録Clear
        If Remcon(0).CheckBox5.Checked Then
            記録.Clear()
            DomainUpDown1.Items.Clear()
            DomainUpDown1.Text = ""
        End If
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs)
        列車(0).区間変化 = True
        列車(1).区間変化 = True
    End Sub

    Private Sub Button3_Click_1(sender As Object, e As EventArgs) Handles Button3.Click

        列車(0).ポイント = &HC0 + NumericUpDown1.Value
        '列車(0).区間変化 = True
        '列車(1).区間変化 = True
    End Sub

    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        列車(0).ポイント = &H80 + NumericUpDown1.Value

    End Sub


    Private Sub Timer2_Tick(sender As Object, e As EventArgs)
        'TM = True
        'Timer2.Enabled = False
    End Sub

    Private Sub Form1_Closed(sender As Object, e As EventArgs) Handles Me.Closed
        csv_writer.Close()
    End Sub

    Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
        Label3.Visible = CheckBox1.Checked

        If CheckBox1.Checked Then
            Me.Width = Label3.Left + Label3.Width + 40
        Else
            Me.Width = GroupBox1.Left + GroupBox1.Width + 40
        End If

    End Sub

    Private Sub Timer2_Tick_1(sender As Object, e As EventArgs) Handles Timer2.Tick
        '停車時間タイマー
        PlayStep += 1

        If 記録.Count <= PlayStep Then
            PlayStep = 0

            If CheckBox2.Checked Then
                'repeat
                TM2 = True
            Else
                'Play終了
                Remcon(0).CheckBox6.Checked = False
                Remcon(0).Speed_Cont = 0
            End If
        End If

        Label2.Text = PlayStep
        DomainUpDown1.SelectedIndex = PlayStep
        Timer2.Enabled = False
        Label4.Text = "TimerOFF"


    End Sub

    Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
        'OpenFileDialogクラスのインスタンスを作成
        Dim ofd As New OpenFileDialog()

        ofd.Filter =
            "Playファイル(*.dat)|*.dat|すべてのファイル(*.*)|*.*"
        ofd.FilterIndex = 1
        'タイトルを設定する
        ofd.Title = "開くファイルを選択してください"

        'ダイアログを表示する
        If ofd.ShowDialog() = DialogResult.OK Then
            'OKボタンがクリックされたとき
            Dim formatter As New BinaryFormatter()
            Dim inputStream As New IO.FileStream(ofd.FileName, IO.FileMode.Open)

            DomainUpDown1.Items.Clear()
            Try
                Dim c As Integer = 0
                記録 = CType(formatter.Deserialize(inputStream), Rec_List)
                For Each rec As Record In 記録

                    'Dim rev As String = "OFF"
                    'If rec.逆転 Then rev = "ON"
                    'Dim point As String = rec.ポイント番号
                    'If rec.ポイント番号 = -2 Then point = "OFF"
                    'Dim yard As String = rec.Yard番号
                    'If rec.Yard番号 = -1 Then yard = "OFF"

                    'Dim mes As String = String.Format("{0} 路線{1} 区間{2} 逆転{3} ポイント{4} Yard{5} 停止時間{6} Speed{7}", _
                    '                    c, rec.位置.路線, rec.位置.区間, rev, point, yard, rec.停止時間, rec.スピード)

                    DomainUpDown1.Items.Add(記録msg(rec, c))
                    c += 1
                Next
                DomainUpDown1.SelectedIndex = 0
            Finally
                inputStream.Close()
                PlayStep = 0
                Remcon(0).CheckBox6.Enabled = True 'Play可
            End Try

        End If


    End Sub

    Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
        'SaveFileDialogクラスのインスタンスを作成
        Dim sfd As New SaveFileDialog()

        'はじめのファイル名を指定する
        sfd.FileName = "新規.dat"
        'はじめに表示されるフォルダを指定する
        'sfd.InitialDirectory = "C:\"
        '[ファイルの種類]に表示される選択肢を指定する
        sfd.Filter = "Playファイル(*.dat)|*.dat|すべてのファイル(*.*)|*.*"
        '[ファイルの種類]ではじめに
        '「すべてのファイル」が選択されているようにする
        sfd.FilterIndex = 1
        'タイトルを設定する
        sfd.Title = "保存先のファイルを選択してください"
        'ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
        'sfd.RestoreDirectory = True
        '既に存在するファイル名を指定したとき警告する
        'デフォルトでTrueなので指定する必要はない
        'sfd.OverwritePrompt = True
        '存在しないパスが指定されたとき警告を表示する
        'デフォルトでTrueなので指定する必要はない
        'sfd.CheckPathExists = True

        'ダイアログを表示する
        If sfd.ShowDialog() = DialogResult.OK Then
            'OKボタンがクリックされたとき
            Console.WriteLine(sfd.FileName)
            Dim formatter As New BinaryFormatter()
            Dim outputStream As New IO.FileStream(sfd.FileName, IO.FileMode.Create)

            Try
                formatter.Serialize(outputStream, 記録)
            Finally
                outputStream.Close()
            End Try
        End If


    End Sub
End Class


ContPanelのコード
Public Class ContPanel

    Public Index As Integer
    Public Event 逆転_Click(ByVal index As Integer)
    Public Event ポイント_Click(ByVal index As Integer)
    Public Event Yard_Click(ByVal index As Integer)
    Public Event Rec_Click()


    Private MaxSpeed As Integer = 150
    Private PowerMeter_max As Integer = &HE8
    Private SpeedMeter_max As Integer = &HA0



    Public Sub New(id As Integer)

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

        Index = id
    End Sub

    Public Property Speed_Cont() As Integer 'Speed コントローラ
        Get
            Return TrackBar1.Value
        End Get

        Set(ByVal Value As Integer)
            TrackBar1.Value = Value
        End Set
    End Property

    Public WriteOnly Property Yard_Cont() As Boolean
        'Yard ボタンなどの操作可否
        Set(ByVal Value As Boolean)
            CheckBox3.Enabled = Value
            CheckBox4.Enabled = Value
            NumericUpDown1.Enabled = Value
            DomainUpDown2.Enabled = Value
            If Value Then
                CheckBox3.Checked = False
            End If
        End Set
    End Property


    Public WriteOnly Property 信号() As String
        Set(ByVal value As String)

            Select Case value
                Case "緑"
                    Label1.BackColor = Color.LightGreen
                Case "黄"
                    Label1.BackColor = Color.Yellow
                Case "赤"
                    Label1.BackColor = Color.LightPink
                Case "灰"
                    Label1.BackColor = Color.LightGray
            End Select
        End Set
    End Property

    Public WriteOnly Property 区間表示() As Byte()
        Set(ByVal value As Byte())

            Dim 区間 = value(0) And &H7
            Dim 路線 = (value(0) And &H38) / 8

            If 路線 <> 7 Then
                Label1.Text = String.Format("現 路線:{0}  区間:{1}", 路線, 区間)

                区間 = value(1) And &H7
                路線 = (value(1) And &H38) / 8
                Label1.Text += String.Format(vbCrLf + "次 路線:{0}  区間:{1}", 路線, 区間)
            Else
                Label1.Text = ""
            End If

        End Set
    End Property



    Public WriteOnly Property Speed_Meter() As Integer  'Speed メーター
        Set(ByVal Value As Integer)
            Dim speed_max As Integer = SpeedMeter_max

            Dim sp As Integer = (1 - Value / speed_max) * PictureBox1.Height

            Dim g As Graphics = Graphics.FromImage(PictureBox1.Image)

            g.Clear(Color.White)

            Dim pen As Pen = New Pen(Color.Red, 3)
            Dim brush As Brush = Brushes.Pink


            Dim p1 As Point = New Point(0, sp)
            Dim p2 As Point = New Point(PictureBox1.Width, sp)

            Dim rect As Rectangle = New Rectangle(p1, New Size(PictureBox1.Width, PictureBox1.Height - sp))

            g.FillRectangle(brush, rect)


            'PictureBox1.Refresh()

        End Set
    End Property

    Public WriteOnly Property Power_Meter() As Integer  'Power メーター
        Set(ByVal Value As Integer)
            Dim speed_max As Integer = PowerMeter_max


            Dim sp As Integer = (1 - Value / speed_max) * PictureBox1.Height

            Dim g As Graphics = Graphics.FromImage(PictureBox1.Image)

            'g.Clear(Color.White)

            Dim pen As Pen = New Pen(Color.Red, 3)
            Dim brush As Brush = Brushes.Pink


            Dim p1 As Point = New Point(0, sp)
            Dim p2 As Point = New Point(PictureBox1.Width, sp)

            g.DrawLine(pen, p1, p2)

            PictureBox1.Refresh()

        End Set
    End Property

    Public Sub add_point(p() As Form1.PointClass)

        Dim n As Integer
        DomainUpDown1.Items.Add("次")

        While p(n) IsNot Nothing
            Dim p_num = p(n).番号

            If Not DomainUpDown1.Items.Contains(p_num) Then
                DomainUpDown1.Items.Add(p(n).番号)
            End If

            n += 1
        End While

        DomainUpDown1.Items.Reverse()
        DomainUpDown1.SelectedIndex = DomainUpDown1.Items.Count - 1
    End Sub

    Public Property point_num As Integer
        Get
            If DomainUpDown1.Text = "次" Then
                Return -1
            Else
                Return Val(DomainUpDown1.Text)
            End If
        End Get

        Set(value As Integer)
            If value = -1 Then
                DomainUpDown1.SelectedIndex = DomainUpDown1.Items.Count '次
            Else
                DomainUpDown1.Text = value
            End If
        End Set

    End Property

    Private Sub ContPanel_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        TrackBar1.Maximum = MaxSpeed
        TrackBar1.TickFrequency = 10

        'スピードメーター用
        Dim bmp As New Bitmap(PictureBox1.Size.Width, PictureBox1.Size.Height)
        PictureBox1.Image = bmp

        NumericUpDown1.Maximum = Form1.yard.Length
        NumericUpDown1.Minimum = 1
        NumericUpDown1_ValueChanged(Nothing, Nothing)


        AddHandler Form1.yard_chg, AddressOf Yard_chg


        If Index = 0 Then
            'Recボタン用checkboxの設定
            'CheckBox5.AutoSize = False
            CheckBox5.Size = New Size(40, 25)
            CheckBox5.TextAlign = ContentAlignment.MiddleCenter

            'Playボタン用checkboxの設定
            'CheckBox6.AutoSize = False
            CheckBox6.Size = New Size(40, 25)
            CheckBox6.TextAlign = ContentAlignment.MiddleCenter
            CheckBox6.Enabled = False
        Else
            CheckBox5.Visible = False
            CheckBox6.Visible = False
        End If

    End Sub

    Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
        RaiseEvent 逆転_Click(Index)
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '停止ボタンでスライダーを0にする()
        TrackBar1.Value = 0
    End Sub

    Private Sub CheckBox2_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox2.CheckedChanged
        RaiseEvent ポイント_Click(Index)
    End Sub

    Private Sub CheckBox3_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox3.CheckedChanged
        RaiseEvent Yard_Click(Index)
    End Sub

    Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged
        Yard_chg()
    End Sub

    Private Sub Yard_chg()
        'yard状況変化
        DomainUpDown2.Items.Clear()
        DomainUpDown2.SelectedIndex = -1

        If Form1.列車(Index).Enable Then
            '入線時
            For Each s In Form1.yard(NumericUpDown1.Value - 1).空線
                DomainUpDown2.Items.Add(s)
            Next
        Else
            '発車時
            For Each s In Form1.yard(NumericUpDown1.Value - 1).在線
                DomainUpDown2.Items.Add(s)
            Next
        End If


        If DomainUpDown2.Items.Count = 0 Then
            DomainUpDown2.Text = "-"
        Else
            DomainUpDown2.SelectedIndex = DomainUpDown2.Items.Count - 1
        End If
    End Sub

    Public Property 線番号 As Integer
        Get
            Return Val(DomainUpDown2.Text)
        End Get

        Set(value As Integer)
            If DomainUpDown2.Items.Contains(value) Then
                DomainUpDown2.Text = value
            End If

        End Set

    End Property

    Private Sub CheckBox5_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox5.CheckedChanged
        'Rec
        RaiseEvent Rec_Click()
    End Sub
End Class