私は現在、完全にc#でコーディングした盗難警報ソリューションに取り組んでいます。プログラムは、アラームセンサーが配線されたUSBシリアルポートベースのIOボードと通信します。DataReceivedイベント内からTextLog(終了を参照)というサブを呼び出さない限り、DataReceivedイベントがメインUIを更新できないという問題があります。奇妙なことに、ゾーン1のクエリからのDataReceivedイベントはメインUIを更新できますが、ゾーン2または3は更新できません。さらに、シリアルポートの書き込みが実行される行にブレークポイントを挿入すると、期待どおりに機能します。
これらのグローバル変数に言及する価値があります:
string ioCardRxString = "";
bool[] arrGlobalZoneStatus = new bool[4];
設定ファイルから設定を読み取ってシリアルポートを開きます(すべて正常に機能します)。
private void OpenIOComPort()
{
bool error = false;
else
{
// Set the port's settings
spIOCard.PortName = Settings1.Default.ioComPort;
spIOCard.BaudRate = int.Parse(Settings1.Default.ioBaudRate);
spIOCard.DataBits = int.Parse(Settings1.Default.ioDataBits);
spIOCard.StopBits = (System.IO.Ports.StopBits)Enum.Parse(typeof(System.IO.Ports.StopBits), Settings1.Default.ioStopBits);
spIOCard.Parity = (System.IO.Ports.Parity)Enum.Parse(typeof(System.IO.Ports.Parity), Settings1.Default.ioParity);
spIOCard.Handshake = (System.IO.Ports.Handshake)Enum.Parse(typeof(System.IO.Ports.Handshake), Settings1.Default.ioHandshake);
try
{
// Open the port
spIOCard.Open();
}
catch (UnauthorizedAccessException) { error = true; }
catch (System.IO.IOException) { error = true; }
catch (ArgumentException) { error = true; }
//On error, advise the user
if (error)
{
MessageBox.Show("Could not open the I/O Board COM port.");
globalIOCardError = true;
}
if (!error)
{
globalIOCardError = false;
// Do Nothing
}
}
}
タイマーは500msごとに実行され、シリアルポートに3つのコマンドを書き込みます。各コマンドは25msで区切られています(ハードウェアの制限)。これらのコマンドは、各アラームセンサーのステータスを判断するためにIOボードにクエリを実行します。
private void tmrAuditSensors_Tick(object sender, EventArgs e)
{
try
{
if (globalIOCardError == false && Settings1.Default.disableSensorAudit == false)
{
if (Settings1.Default.zone1Armed == true)
{
spIOCard.Write("~in01~");
System.Threading.Thread.Sleep(25);;
}
if (Settings1.Default.zone2Armed == true)
{
spIOCard.Write("~in02~");
System.Threading.Thread.Sleep(25);;
}
if (Settings1.Default.zone3Armed == true)
{
spIOCard.Write("~in03~");
System.Threading.Thread.Sleep(25);;
}
//Applicable results will appear on serial data received event
}
}
catch
{
textLog("There was a problem writing to the serial port, check and restart app");
emergencyHalt();
}
}
Serial Port DataReceivedイベントは、返された文字列を読み取り、ブール値のグローバル配列に書き込みます。そのゾーンが開いている場合(= 1)はTrue、閉じている場合(= 0)はFalseです。注:スター付きの線。
private void spIO_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
ioCardRxString = spIOCard.ReadExisting();
textLog(ioCardRxString); //*Cannot make it work without this
if (ioCardRxString.Contains("in05=1") == true)
{
arrGlobalZoneStatus[1] = true;
}
if (ioCardRxString.Contains("in05=0") == true)
{
arrGlobalZoneStatus[1] = false;
}
if (ioCardRxString.Contains("in01=1") == true)
{
arrGlobalZoneStatus[2] = true;
}
if (ioCardRxString.Contains("in01=0") == true)
{
arrGlobalZoneStatus[2] = false;
}
if (ioCardRxString.Contains("in17=1") == true)
{
arrGlobalZoneStatus[3] = true;
}
if (ioCardRxString.Contains("in17=0") == true)
{
arrGlobalZoneStatus[3] = false;
}
}
これとは別に、別のタイマーが定期的に(250msごとに)各配列メンバーの内容をチェックし、それに応じてメインUIを色の変更とテキストの更新で更新します。
private void tmrCheckZoneStatus_Tick(object sender, EventArgs e)
{
if (arrGlobalZoneStatus[1] == true)
{
button10.BackColor = System.Drawing.Color.Red;
textLog(button10.Text + " was activated");
if (globalFullAlarmSet || globalNightAlarmSet || globalDoorsAlarmSet)
{
this.BeginInvoke(new EventHandler(delegate { checkAndActivateRelays(1); }));
}
}
if (arrGlobalZoneStatus[1] == false)
{
button10.BackColor = System.Drawing.Color.Gray;
}
if (arrGlobalZoneStatus[2] == true)
{
button11.BackColor = System.Drawing.Color.Red;
textLog(button11.Text + " was activated"); ;
if (globalFullAlarmSet || globalNightAlarmSet || globalDoorsAlarmSet)
{
this.BeginInvoke(new EventHandler(delegate { checkAndActivateRelays(2); }));
}
}
if (arrGlobalZoneStatus[2] == false)
{
button11.BackColor = System.Drawing.Color.Gray;
}
if (arrGlobalZoneStatus[3] == true)
{
button12.BackColor = System.Drawing.Color.Red;
textLog(button12.Text + " was activated");
if (globalFullAlarmSet || globalNightAlarmSet || globalDoorsAlarmSet)
{
this.BeginInvoke(new EventHandler(delegate { checkAndActivateRelays(3); }));
}
}
if (arrGlobalZoneStatus[3] == false)
{
button12.BackColor = System.Drawing.Color.Gray;
}
}
textLog sub:
public void textLog(string logEntry)
{
textLines++;
try
{
if (this.txtLog.InvokeRequired)
{
ChangeTextCallback MethodCallback = new ChangeTextCallback(textLog);
this.Invoke(MethodCallback, new object[] { logEntry });
}
else
{
if (!logEntry.Contains("?"))
{
txtLog.Text = txtLog.Text + DateTime.Now + " >: " + logEntry + "\r\n";
txtLog.SelectionStart = txtLog.Text.Length;
txtLog.ScrollToCaret();
if (textLines > 3000)
{
txtLog.Clear();
textLines = 0;
textLog("Text log cleared");
}
System.IO.StreamWriter sw = new System.IO.StreamWriter(logFile, true);
try
{
sw.WriteLine(DateTime.Now + " >: " + logEntry);
}
catch (Exception ex)
{
//
}
sw.Close();
}
}
}
catch
{
//
}
}
どこかにinvoke/delegateを組み込む必要があると思いますが、初心者として頭を悩ませています。あなたの助けをいただければ幸いです。
ありがとう