0

私はデバイスとインターフェイスしており、C# を使用してデバイスから約 2000 バイトを送受信しています。接続ボタンをクリックしてそのまま実行すると、プロセスは 80% の確率で完了し、20% の確率で読み取りタイムアウトが発生します。これ自体が問題です。

さらに、データの読み取り中にウィンドウを移動すると、読み取りタイムアウトが発生します。優先度の問題かもしれないと思ったので、バックグラウンド ワーカーとインターフェイス スレッドの優先度をいじってみましたが、うまくいきませんでした。

誰かが以前にこれを経験したことがありますか? そして、アドバイスをいただければ幸いです。以下は関連するコードです。さらに多くのコードが必要だと思われる場合はお知らせください。同様に投稿します。前もって感謝します。

関数が呼び出される場所:

        private void connectButton_Click(object sender, RoutedEventArgs e) //Connect button clicked
    {
        if (!Global.isConnected)
        {
            agentradioread.connect((string)portsOpen.SelectedValue, this);
            form.deviceConnecting(this);
        }
        else
        {
            agentradioread.disconnect();
            form.deviceDisconnect(this);
        }
    }

    private void loadSettings_Click(object sender, RoutedEventArgs e) //Loads settings
    {
        if (Global.isConnected)
        {
            agentradioread.readValues(this);
        }
    }

    private void sendSettings_Click(object sender, RoutedEventArgs e) //Sends settings
    {
        if (Global.isConnected)
        {
            agentradioread.readTime();
            string minutes = (Create.sysval[10].ToString().Length == 1) ? "0" + Create.sysval[10].ToString() : Create.sysval[10].ToString();
            string date = Create.sysval[11].ToString() + "/" + Create.sysval[12].ToString() + "/20" + Create.sysval[13].ToString();
            string time = Create.sysval[9].ToString() + ":" + minutes;
            MessageBoxResult result = MessageBox.Show("The current device date and time is: " + date + " " + time + "\r\nIs this time correct?", "Date & Time Verification", MessageBoxButton.YesNo, MessageBoxImage.Question);

            if (result == MessageBoxResult.Yes) //Time is correct
            {
                Create.sysval[9] = 255;
            }
            else //Time is incorrect
            {
                dateTimeChange dateTime = new dateTimeChange();
                dateTime.ShowDialog();
            }

            agentradioread.sendValues(this);
        }
    }

呼び出される関数:

public void connect(string selectedPort, agentRadio agentR) //Connects device and reads values
{
        agentSerial = new SerialPort(selectedPort, 9600, Parity.None, 8, StopBits.One);

        connectWorker = new BackgroundWorker();
        connectWorker.WorkerReportsProgress = true;
        connectWorker.DoWork += new DoWorkEventHandler(connectWorker_DoWork);
        connectWorker.ProgressChanged += new ProgressChangedEventHandler(connectWorker_ProgressChanged);

        connectWorker.RunWorkerAsync(agentR);
    }

    public void readTime() //Reads time into sysval locations
    {
        agentSerial.DiscardInBuffer();
        agentSerial.DiscardOutBuffer();
        agentSerial.Write(Global.TIME, 0, Global.TIME.Length); //begin send values
        loadTime();
    }

    public void readValues(agentRadio agentR) //Read values
    {
        readWorker = new BackgroundWorker();
        readWorker.WorkerReportsProgress = true;
        readWorker.DoWork += new DoWorkEventHandler(readWorker_DoWork);
        readWorker.ProgressChanged += new ProgressChangedEventHandler(readWorker_ProgressChanged);

        agentSerial.DiscardInBuffer();
        agentSerial.DiscardOutBuffer();
        readWorker.RunWorkerAsync(agentR);
    }

    public void sendValues(agentRadio agentR) //Send values
    {
        sendWorker = new BackgroundWorker();
        sendWorker.WorkerReportsProgress = true;
        sendWorker.DoWork += new DoWorkEventHandler(sendWorker_DoWork);
        sendWorker.ProgressChanged += new ProgressChangedEventHandler(sendWorker_ProgressChanged);

        agentSerial.DiscardInBuffer();
        agentSerial.DiscardOutBuffer();
        sendWorker.RunWorkerAsync(agentR);
    }

    public void restoreDevice(agentRadio agentR) //Restore device to defaults
    {
        agentSerial.DiscardInBuffer();
        agentSerial.DiscardOutBuffer();
        agentSerial.Write(Global.RESTORE, 0, Global.RESTORE.Length); //device restore command
        MessageBox.Show(agentSerial.ReadByte().ToString());
        try
        {
            Global.restoring = true;
            readValues(agentR);
        }
        catch
        {
            MessageBox.Show("Your device was restored, but a read time out occured. You need to go to the connect tab and reconnect to the device, and your settings will update.", "Device Restore Notice", MessageBoxButton.OK, MessageBoxImage.Information);
        }
    }

    public void disconnect() //Disconnects device
    {
        if (Global.isConnected == true)
        {
            try
            {
                agentSerial.DiscardInBuffer();
                agentSerial.DiscardOutBuffer();
                agentSerial.Write(Global.EXIT_PROGRAM, 0, Global.EXIT_PROGRAM.Length);
            }
            catch
            {
                //leave option to reConnect
            }
            agentSerial.Close();
            Global.isConnected = false;
        }
    }

    /*Methods that cannot be called from elsewhere in the application*/

    private void connectWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) //Updates progressbar while device is connecting
    {
        ProgressBar progressBar = e.UserState as ProgressBar;

        App.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Send,
                new Action(
                    delegate()
                    { progressBar.Value = e.ProgressPercentage; }));
    }

    private void connectWorker_DoWork(object sender, DoWorkEventArgs e) //Connects and read values
    {
        startRead((agentRadio)e.Argument);
    }

    private void readWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) //Alerts user when values are loaded
    {
        ProgressBar progressBar = e.UserState as ProgressBar;

        App.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Send,
                new Action(
                    delegate()
                    { progressBar.Value = e.ProgressPercentage; }));
    }

    private void readWorker_DoWork(object sender, DoWorkEventArgs e) //Reads values
    {
        agentRadio agentR = (agentRadio)e.Argument;

        App.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Send,
                new Action(
                    delegate()
                    { form.deviceReading(agentR); }));

        agentSerial.Write(Global.READ_VALUES, 0, Global.READ_VALUES.Length); //begin read values

        byte key = (byte)agentSerial.ReadByte();

        if (Global.START_COMMAND == key) //Verify continue key
        {
            object progressBarObject = new object();
            progressBarObject = agentR.connectProgress;

            for (int i = 1; i < 2247; i++) //Loop through values, calling read function and updating progress bar
            {
                int progress = (int)(((float)i / 2246.0) * 100);
                readWorker.ReportProgress(progress, progressBarObject);

                try
                {
                    readData(i, agentR);
                    agentSerial.Write(Global.GO_AHEAD, 0, Global.GO_AHEAD.Length);

                    agentSerial.DiscardInBuffer();
                    agentSerial.DiscardOutBuffer();
                }
                catch
                {
                    break;
                }
            }
        }
        else //Key failed and displays error
        {
            App.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Send,
                    new Action(
                        delegate()
                        { form.deviceDisconnect(agentR); }));
            MessageBox.Show("Connection Failed, Invalid Key");
        }
    }

    private void sendWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) //Alerts user when values are sent
    {
        ProgressBar progressBar = e.UserState as ProgressBar;

        App.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Send,
                new Action(
                    delegate()
                    { progressBar.Value = e.ProgressPercentage; }));
    }

    private void sendWorker_DoWork(object sender, DoWorkEventArgs e) //Sends values
    {
        agentRadio agentR = (agentRadio)e.Argument;

        App.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Send,
                new Action(
                    delegate()
                    { form.deviceSending(agentR); }));

        agentSerial.Write(Global.SEND_VALUES, 0, Global.SEND_VALUES.Length); //begin send values

        byte key = (byte)agentSerial.ReadByte();

        if (Global.START_COMMAND == key) //Verify continue key
        {
            object progressBarObject = new object();
            progressBarObject = agentR.connectProgress;

            for (int i = 1; i < 659; i++) //Loops and sends data to device
            {
                int progress = (int)(((float)i / 658.0) * 100);
                sendWorker.ReportProgress(progress, progressBarObject);

                try
                {
                    byte result = sendData(i, agentR);

                    if (result != Global.GO_AHEAD[0])
                    {
                        MessageBox.Show("Fatal Error");
                        break;
                    }

                    agentSerial.DiscardInBuffer();
                    agentSerial.DiscardOutBuffer();
                }
                catch
                {
                    break;
                }
            }
        }
        else //Key failed and displays error
        {
            App.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Send,
                    new Action(
                        delegate()
                        { form.deviceDisconnect(agentR); }));
            MessageBox.Show("Connection Failed, Invalid Key");
        }
    }

    private void loadTime() //Loads device time into sysval locations
    {
        byte key = (byte)agentSerial.ReadByte();

        if (Global.START_COMMAND == key) //Verify continue key
        {
            for (int i = 0; i < 5; i++)
            {
                try
                {
                    byte result = (byte)agentSerial.ReadByte();
                    Create.sysval[9 + i] = result;
                }
                catch
                {
                    Create.sysval[9 + i] = 0;
                }
            }
            agentSerial.ReadByte();
        }

        agentSerial.DiscardInBuffer();
        agentSerial.DiscardOutBuffer();
    }

    private string sendInitial() //Sends a ? and returns 7 bytes of data
    {
        string handshake = "";
        agentSerial.Write("?");

        for (int i = 0; i < 7; i++)
        {
            try
            {
                handshake += agentSerial.ReadByte().ToString();
            }
            catch
            {
                break;
            }
        }

        return handshake;
    }

    private void startRead(agentRadio agentR) //Initializes data send and receive
    {
        System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;
        App.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Send,
                new Action(
                    delegate()
                    { agentR.connectProgress.IsIndeterminate = true; }));

        agentSerial.ReadTimeout = 5000;
        agentSerial.Open();

        agentSerial.DiscardInBuffer();
        agentSerial.DiscardOutBuffer();

        string handshake = sendInitial();

        if (handshake == Global.AGENT_RADIO) //Result matches agent radio version
        {
            agentSerial.Write(Global.READ_VALUES, 0, Global.READ_VALUES.Length); //begin read values

            byte key = (byte)agentSerial.ReadByte();

            if (Global.START_COMMAND == key) //Verify continue key
            {
                App.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Send,
                    new Action(
                        delegate()
                        { agentR.connectProgress.IsIndeterminate = false; }));

                object progressBarObject = new object();
                progressBarObject = agentR.connectProgress;

                for (int i = 1; i < 2247; i++) //Loop through values, calling read function and updating progress bar
                {
                    int progress = (int)(((float)i / 2246.0) * 100);
                    connectWorker.ReportProgress(progress, progressBarObject);

                    try
                    {
                        readData(i, agentR);
                        agentSerial.Write(Global.GO_AHEAD, 0, Global.GO_AHEAD.Length);

                        agentSerial.DiscardInBuffer();
                        agentSerial.DiscardOutBuffer();
                    }
                    catch
                    {
                        break;
                    }
                }
            }
            else //Key failed and displays error
            {
                agentSerial.Close();
                App.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Send,
                    new Action(
                        delegate()
                        { form.deviceDisconnect(agentR); }));
                MessageBox.Show("Connection Failed, Invalid Key");
            }
        }
        else //Result did not match an agent radio version
        {
            agentSerial.Close(); //Closes port

            if (attempt < 3) //Attempt to connect to device 5 times
            {
                attempt++;
                startRead(agentR);
            }
            else //Displays error to user if connection failed
            {
                App.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Send,
                    new Action(
                        delegate()
                        { form.deviceDisconnect(agentR); }));
                MessageBox.Show("Connection Failed, Not Agent Radio Version");
            }
        }
    }

    private void readData(int iteration, agentRadio agentR) //Reads data for current iteration
    {
        byte value = 0; //Current value

        try
        {
            value = (byte)agentSerial.ReadByte(); //Reads byte
        }
        catch
        {
            agentSerial.Close();
            App.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Send,
                    new Action(
                        delegate()
                        { form.deviceDisconnect(agentR); }));
            MessageBox.Show("Connection Failed, Read Timeout"); //Displays message if read timeout occured
        }

        if (iteration > 0 && iteration < 385) //read schedule
        {
            double pos = (iteration - 1) / 48;

            int i = (int)Math.Floor(pos);
            int j = (iteration - 1) - (i * 48);

            Create.schedule[i, j] = value;
        }

        if (iteration > 384 && iteration < 1285) //read alarm history
        {
            double pos = (iteration - 385) / 9;

            int i = (int)Math.Floor(pos);
            int j = (iteration - 385) - (i * 9);

            Create.alarms[i, j] = value;
        }

        if (iteration > 1284 && iteration < 1345) //read error log
        {
            double pos = (iteration - 1285) / 6;

            int i = (int)Math.Floor(pos);
            int j = (iteration - 1285) - (i * 6);

            Create.errors[i, j] = value;
        }

        if (iteration > 1344 && iteration < 1945) //read voltage history
        {
            double pos = (iteration - 1345) / 6;

            int i = (int)Math.Floor(pos);
            int j = (iteration - 1345) - (i * 6);

            Create.voltage[i, j] = value;
        }

        if (iteration > 1944 && iteration < 1973) //read holidays
        {
            Create.holidays[iteration - 1945] = value;
        }

        if (iteration > 1972 && iteration < 2168) //read message sequences
        {
            double pos = (iteration - 1973) / 15;

            int i = (int)Math.Floor(pos);
            int j = (iteration - 1973) - (i * 15);

            Create.messages[i, j] = value;
        }

        if (iteration > 2167 && iteration < 2196) //read message info
        {
            Create.recordings[iteration - 2168] = value;
        }

        if (iteration > 2195 && iteration < 2246) //read sysval
        {
            Create.sysval[iteration - 2196] = value;
        }

        if (iteration == 2246 && value == Global.FINISH_COMMAND)
        {
            if (Global.restoring)
            {
                App.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Send,
                    new Action(
                        delegate()
                        { form.deviceConnect(agentR); }));
                MessageBox.Show("Your device has been restored, and all settings from the device have been received.", "Device Restore Succesful", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            else
            {
                App.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Send,
                    new Action(
                        delegate()
                        { form.deviceConnect(agentR); }));
                Global.isConnected = true;
                MessageBox.Show("Your device is connected, and all settings from the device have been received.", "Data Transfer Succesful", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }
    }

    private byte sendData(int iteration, agentRadio agentR) //Sends data for current iteration
    {
        byte value = 0; //For return later

        if (iteration > 0 && iteration < 51) //sysval
        {
            byte[] toWrite = new byte[1];
            toWrite[0] = Create.sysval[iteration - 1];
            agentSerial.Write(toWrite, 0, 1);

            value = (byte)agentSerial.ReadByte();
        }
        if (iteration > 50 && iteration < 79) //holiday
        {
            byte[] toWrite = new byte[1];
            toWrite[0] = Create.holidays[iteration - 51];
            agentSerial.Write(toWrite, 0, 1);

            value = (byte)agentSerial.ReadByte();
        }
        if (iteration > 78 && iteration < 463) //schedule
        {
            double pos = (iteration - 79) / 48;

            int i = (int)Math.Floor(pos);
            int j = (iteration - 79) - (i * 48);

            byte[] toWrite = new byte[1];
            toWrite[0] = Create.schedule[i, j];
            agentSerial.Write(toWrite, 0, 1);

            value = (byte)agentSerial.ReadByte();
        }
        if (iteration > 462 && iteration < 658) //message sequence
        {
            double pos = (iteration - 463) / 15;

            int i = (int)Math.Floor(pos);
            int j = (iteration - 463) - (i * 15);

            byte[] toWrite = new byte[1];
            toWrite[0] = Create.messages[i, j];
            agentSerial.Write(toWrite, 0, 1);

            value = (byte)agentSerial.ReadByte();
        }

        if (iteration == 658 && ((byte)agentSerial.ReadByte() == Global.FINISH_COMMAND)) //Last iteration should get finish command
        {
            App.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Send,
                    new Action(
                        delegate()
                        { form.deviceConnect(agentR); }));
            MessageBox.Show("Your settings have been transfered succesfully to the device.", "Successful Transfer", MessageBoxButton.OK, MessageBoxImage.Information);

            value = 17; //Simulates GO_AHEAD character for last iteration of loop
        }

        return value; //Return character off port, should be GO_AHEAD
    }
}

フォーム クラス:

public string[] populateAvailablePorts() //Returns string array of open ports
    {
        String[] portsAvailable = SerialPort.GetPortNames();
        return portsAvailable;
    }

    public void deviceConnect(agentRadio agentR) //Adjusts display for when device is disconnected
    {
        agentR.portsOpen.IsEnabled = false;
        agentR.connectButton.Content = "Disconnect";
        agentR.connectButton.IsEnabled = true;
        agentR.connectProgress.Value = 100;
        agentR.loadSettingsConnect.Content = "Load Settings";
        agentR.sendSettingsConnect.Content = "Send Settings";
        agentR.loadSettingsConnect.IsEnabled = true;
        agentR.sendSettingsConnect.IsEnabled = true;
        agentR.DeviceRestore.IsEnabled = true;

        agentR.VoltageStack.Children.Clear();
        agentR.ErrorStack.Children.Clear();
        agentR.Events.Children.Clear();

        agentR.DeviceRestore.IsEnabled = true;

        display.setDisplay(agentR);
    }

    public void deviceConnecting(agentRadio agentR) //Adjusts display for when device is disconnected
    {
        agentR.portsOpen.IsEnabled = false;
        agentR.connectButton.Content = "Connecting...";
        agentR.connectButton.IsEnabled = false;
        agentR.loadSettingsConnect.IsEnabled = false;
        agentR.sendSettingsConnect.IsEnabled = false;
        agentR.DeviceRestore.IsEnabled = false;
    }

    public void deviceReading(agentRadio agentR) //Adjusts display for when device is disconnected
    {
        agentR.connectButton.IsEnabled = false;
        agentR.loadSettingsConnect.Content = "Reading Data...";
        agentR.loadSettingsConnect.IsEnabled = false;
        agentR.sendSettingsConnect.IsEnabled = false;
        agentR.DeviceRestore.IsEnabled = false;
    }

    public void deviceSending(agentRadio agentR) //Adjusts display for when device is disconnected
    {
        agentR.connectButton.IsEnabled = false;
        agentR.sendSettingsConnect.Content = "Sending Data...";
        agentR.loadSettingsConnect.IsEnabled = false;
        agentR.sendSettingsConnect.IsEnabled = false;
        agentR.DeviceRestore.IsEnabled = false;
    }

    public void deviceDisconnect(agentRadio agentR) //Adjusts display for when device is diconnected
    {
        agentR.portsOpen.IsEnabled = true;
        agentR.connectButton.IsEnabled = true;
        agentR.connectButton.Content = "Connect";
        agentR.loadSettingsConnect.Content = "Load Settings";
        agentR.sendSettingsConnect.Content = "Send Settings";
        agentR.connectProgress.Value = 0;
        agentR.connectProgress.IsIndeterminate = false;
        agentR.loadSettingsConnect.IsEnabled = false;
        agentR.sendSettingsConnect.IsEnabled = false;

        agentR.DeviceRestore.IsEnabled = false;
    }
4

1 に答える 1

0

DoWork ハンドラーで ProgressBar オブジェクトを使用しないでください。ProgressChanged ハンドラー (readWorker_ProgressChanged) は、進行状況を報告するために必要なものをすべて取得する必要があります。

また、なぜ IsIndeterminate の設定をディスパッチするのですか?

また。ProgressChanged ハンドラーは常に UI スレッドで呼び出されます (自分で直接呼び出さない限り、readWorker_ProgressChanged で何もディスパッチする必要はありません。

また、deviceReading や deviceDisconnect などのフォームに手動でディスパッチすることも避けます。それが進捗イベントの目的です。

これを避ける理由は、これらの操作のために UI スレッドに送り返すためです。これは、UI がこれらのアクションを呼び出すことができるまで、バックグラウンド スレッドがブロックされることを意味します。UI が画面の再描画やメニュー選択の処理でビジー状態の場合、このアクションを処理できません。これにより、UI スレッドが処理できるようになるまでバックグラウンド作業が停止し、シリアル通信がタイムアウトになります。

于 2012-07-17T15:51:29.923 に答える