Potrzebuję obsłużyć sekwencję komend-odpowiedzi do pewnego urządzenia podłączonego po porcie szeregowym.
Z grubsza taka przykładowa sekwencja wygląda tak;
// ***********************************************************************************
// PC:: OPEN PORT,
// => X, <=0x10,
// => V [171B], <=0x06 0x1e 0x34 0x30 0x32 0x03,
// =>S, <=0x06 0x1e 0x34 0x30 0x32 0x03,
// <= 96xVALUE+HEADER [???B],
// =>X, <=0x10,
// CLOSE PORT ::READER
// ***********************************************************************************
Odpowiedzi symuluję wysyłając odpowiednie znaki, lub sekwencje z RealTerm'a. Co do zasady trochę działa, ale...
Problem, który napotkałem polega na tym, że w mojej zmiennej ReaderAnswer (public string ReaderAnswer zadeklarowane w ciele głównego formularza Form1 ) pojawia się odebrana dana, ale dopiero po kliknięciu testowego MessageBox'a (poniżej fragment kodu), a bez MessageBox'a wartość pojawia się dopiero po IF (oczywiście wszystko wysłane na czas, ale obsługa portu szeregowego to iny wątek, Delegate, Invoke, itd.). Wstrzymywanie UI jest akceptowalne, więc używam ThreadSleep() żeby dać sobie szansę na wysłanie symulowanej odpowiedzi, ale jeśli nie będzie tych MessageBox'ów na kolejnych etapach, to dane są jakby spóźnione w mojej sekwencji, a tym samym nigdy się to nie wykona poprawnie. Innymi słowy zatrzymywanie wątku UI przez ThreadSleep niczego nie wnosi (choćbym czekał bardzo długo), a dane odczytane z bufora portu pojawiają się w mojej zmiennej tylko po zaklikaniu MessageBox'a.
Może komuś z Was przyjdzie coś do głowy, może robię jakiś oczywisty błąd...
// ******** START/STOP reading ********
private void pictureBox_startReading_Click(object sender, EventArgs e)
{
bool _error = false;
bool _readingEnabled = true;
while (_readingEnabled)
{
connect(); // Open port
Thread.Sleep(200);
//step 1
ReaderAnswer = string.Empty;
expectedReaderAnswer = BiotekReader.biotek_str_dle_hex; // "\x10";
expectedReaderAnswerLength = expectedReaderAnswer.Length;
Send_Biotek_X();
Thread.Sleep(2000); // muszę mieć czas na odpowiedź
MessageBox.Show("1"); // KLUCZOWY MessageBox - jeśli go nie będzie, poniższy IF ustawi _error
//MessageBox.Show(ReaderAnswer + " : " + expectedReaderAnswer);
if (String.Equals(ReaderAnswer, expectedReaderAnswer))
{
//MessageBox.Show(ReaderAnswer + " ok1 :-)"); //
}
else
{
MessageBox.Show(ReaderAnswer + " !! ok 1" + "\n" + " ;-(");
_error = true;
break;
}
//MessageBox.Show(ReaderAnswer + " : " + expectedReaderAnswer); // poglądając wartość ReaderAnswer będzie ona OK na tym etapie mimo,
// że przed IF'em powyżej była Empty
Thread.Sleep(1000);
//step 2
ReaderAnswer = string.Empty;
expectedReaderAnswer = BiotekReader.biotek_str_status_6B_hex_2; //!!
expectedReaderAnswerLength = expectedReaderAnswer.Length;
Send_Biotek_V();
Thread.Sleep(2000);
MessageBox.Show("2"); // kolejny KLUCZOWY dla poniższego IF'a MessageBox
rtbox_test_RX.AppendText(" <" + ReaderAnswer);
if (String.Equals(ReaderAnswer, expectedReaderAnswer))
...
...
...
// delegate used for Invoke
internal delegate void StringDelegate(string data);
/// <summary>
/// Handle data received event from serial port.
/// </summary>
/// <param name="data">incoming data</param>
public void OnDataReceived(string dataIn)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnDataReceived), new object[] { dataIn });
return;
}