public byte size; /// 読み出しバイト数 #endregion Fields #region Methods public CommandStruct Clone() { CommandStruct image = new CommandStruct(); image.Cmd = this.Cmd; image.Address = this.Address; image.size = this.size; if (this.Data != null) { image.Data = new ushort[this.Data.Length]; for (int i = 0; i < Data.Length; i++) { image.Data[i] = this.Data[i]; } } return image; }
/// <summary> /// コマンドを実行します。 /// </summary> /// <param name="cmd"></param> protected void execCommand(CommandStruct cmd, CommandStruct cmd2 = null) { CommandStruct res = new CommandStruct(); // 共用メモリの更新 switch (cmd.Cmd) { case 'r' : /* 読み込み要求Ack処理 */ case 'W': /* 書き込み要求処理 */ // 機械メモリに書き込み Array.Copy(cmd.Data, 0, machineMem, cmd.Address, cmd.size); Array.Copy(cmd.Data, 0, pcMem, cmd.Address, cmd.size); // メモリ書き換えイベント発生 if (memoryDataChange != null) { MemChangeEventArgs e = new MemChangeEventArgs(); e.Address = sendAckCommand.Address; e.Count = sendAckCommand.size; ctl.Invoke(memoryDataChange, new object[] { this, e }); ts.TraceInformation("メモリ書き換えイベント"); } ts.TraceInformation(cmd.ToString()); break; case 'w': /* 書き込み要求Ack処理 */ Array.Copy(pcMem, cmd2.Address, machineMem, cmd2.Address, cmd2.Data.Length); cmd2.Cmd = 'w'; ts.TraceInformation(cmd2.ToString()); break; case 'R': /* 読み込み要求処理 */ ts.TraceInformation(cmd.ToString()); break; } }
/// <summary> /// バイトデータをデコードしてコマンドを識別します。 /// デコードできない場合、または、チェックサムが異なる場合は、 /// 例外が発生します。 /// </summary> /// <param name="byteImage">コマンドデータ</param> /// <returns>コマンドイメージクラスを返却</returns> public static CommandStruct decodeCommand(byte []byteImage) { CommandStruct cmdImage = new CommandStruct(); Debug.Assert(byteImage != null); // STBチェック if (byteImage[0] != STB) { throw new ArgumentException("STB異常"); } // コマンド種別チェック char cmd = (char)byteImage[2]; if (cmd != 'r' && cmd != 'R' && cmd != 'w' && cmd != 'W') { throw new ArgumentException("コマンド異常"); } // 受信バイト数とデータ数が合わない場合は、エラー if ((byteImage.Length - 4) != byteImage[1]) { throw new ArgumentException("サイズ異常"); } // ENBチェック if (byteImage.Last() != ENB) { throw new ArgumentException("ENB異常"); } // データを取得 cmdImage.Cmd = cmd; switch (cmd) { case 'R': /* 読み込み要求 */ { cmdImage.Address = BitConverter.ToUInt16(byteImage, 3); // チェックサムチェック byte orgFcs = byteImage[6]; byte calcFcs = CalcChecksum(byteImage, 6); // チェックサムエラー if (orgFcs != calcFcs) { throw new ArgumentException("チェックサム異常(R)"); } cmdImage.size = byteImage[5]; } break; case 'w': /* 書き込みAck */ { // チェックサムチェック byte orgFcs = byteImage[3]; byte calcFcs = CalcChecksum(byteImage, 3); // チェックサムエラー if (orgFcs != calcFcs) { throw new ArgumentException("チェックサム異常(w)"); } } break; case 'W': /* 書き込み要求 */ case 'r': /* 読み込みAck */ { cmdImage.Address = BitConverter.ToUInt16(byteImage, 3); byte count = (byte)((byteImage[1] - 3) / 2); /* データ数 */ int n = 5; /* データ開始位置 */ // バイト数をセット cmdImage.size = count; // チェックサムチェック byte orgFcs = byteImage[byteImage.Length - 2]; byte calcFcs = CalcChecksum(byteImage, byteImage.Length - 2); // チェックサムエラー if (orgFcs != calcFcs) { throw new ArgumentException("チェックサム異常(W)"); } // データ部分をデコード cmdImage.Data = new ushort[count]; for (int i = 0; i < count; i++) { cmdImage.Data[i] = BitConverter.ToUInt16(byteImage, n); n += 2; } } break; } return cmdImage; }
/// <summary> /// 送ったコマンドに対応するAckかチェックします。 /// </summary> /// <param name="sent"></param> /// <param name="ack"></param> /// <returns></returns> public static bool CheckAckCommand(CommandStruct sent, CommandStruct ack) { if (sent.Cmd.ToString().ToLower() != ack.Cmd.ToString()) { return false; } return true; }
/// <summary> /// 送信処理 /// </summary> protected void sendTask() { switch (sendStatus) { case SendStatus.Ready : /* 送信予約待ち */ // 送信データありの場合 if (sendQueue.Count > 0) { // コマンドを取り出す sendCommand = ((CommandStruct)sendQueue.Peek()).Clone(); isPolling = false; } // ポーリングタイムアウト発生 else if (isPolling) { sendCommand = new CommandStruct(); sendCommand.Cmd = 'R'; sendCommand.Address = 0x000A; sendCommand.size = 1; } // それ以外 else { return; } // リトライ回数を初期化 sendRetryCount = 0; sendStatus = SendStatus.Sending; break; case SendStatus.Sending : /* 送信中 */ // コマンドをバイト列に変換する byte[] cmd = sendCommand.Encode(); // コマンドを送信する。 try { write(cmd, 0, cmd.Length); sendTimer.Restart(); sendStatus = SendStatus.AckWaiting; } catch { ts.TraceInformation("Write処理失敗"); execSendRetry(); return; } break; case SendStatus.AckWaiting : /* Ack待ち */ // タイムアウト発生の場合はリトライ処理を行う。 if (sendTimer.ElapsedMilliseconds > timeout) { ts.TraceInformation("Ack待ちタイムアウトが発生"); execSendRetry(); return; } break; case SendStatus.CommandProcessing : /* コマンド実行 */ // 不正Ackの場合は、リトライを行う。 if (CommandUtil.CheckAckCommand(sendCommand, sendAckCommand) == false) { ts.TraceInformation("不正Ack受信"); execSendRetry(); return; } // Online状態でなければ、Onlineに切り替え if (status != Status.Online) { // 切断理由をリセットする comError = SystemConstants.COM_ERROR_NORMAL; // StatusをOnlineにする。 status = Status.Online; // 接続イベント発生 if (connstatusChange != null) { ConnStatusEventArgs e = new ConnStatusEventArgs(); e.EventCode = SystemConstants.EVENT_CONNECT; ctl.Invoke(connstatusChange, new object[] { this, e }); } } // コマンド実行 execCommand(sendAckCommand, sendCommand); // ポーリング通信の場合 if (isPolling) { // ポーリング状態の解除 isPolling = false; } // キューからのデータ指示の場合 else { // キューから1件データを削除する sendQueue.Dequeue(); } sendStatus = SendStatus.Ready; break; } }
/// <summary> /// Ack返信処理 /// </summary> /// <param name="cmd"></param> protected void respondAck(CommandStruct cmd) { byte[] commandImage = null; // レスポンス処理 if (cmd.Cmd == 'W') { commandImage = CommandUtil.EncodeCommand('w'); } else if (cmd.Cmd == 'R') { ushort[] data = new ushort[cmd.size]; //Array.Copy(machineMem, cmd.Address, data, 0, cmd.size); for (int i = 0; i < cmd.size; i++) { data[i] = (ushort)machineMem[cmd.Address+i]; } commandImage = CommandUtil.EncodeCommand('r', cmd.Address, data); } // データ送信 try { write(commandImage, 0, commandImage.Length); } catch { ts.TraceInformation("Ack返信処理で例外発生"); } }
/// <summary> /// 受信処理 /// </summary> protected void recvTask() { int bytesToRead = 0; switch (recvStatus) { case RecvStatus.Ready: // バイト数チェック try { bytesToRead = serialPort.BytesToRead; if (bytesToRead < 1) { return; } // ヘッダチェック read(buffer, 0, 1); } catch { ts.TraceInformation("readで例外発生"); return; } // 受信ヘッダチェック if (CommandUtil.CheckHeader(buffer) == false) { ts.TraceInformation("受信ヘッダチェック異常"); return; } recvStatus = RecvStatus.HeaderReading; break; case RecvStatus.HeaderReading : // バイト数チェック try { bytesToRead = serialPort.BytesToRead; if (bytesToRead < 1) { return; } // ヘッダチェック read(buffer, 1, 1); } catch { ts.TraceInformation("readで例外発生"); return; } recvStatus = RecvStatus.CommandProcessing; break; case RecvStatus.CommandProcessing: // 本文チェック byte bodyLength = buffer[1]; try { // 本文の長さ以上のデータが読み込めれば続行する。 bytesToRead = serialPort.BytesToRead; if (bytesToRead < bodyLength+2) { return; } // 本文読み込み read(buffer, 2, bodyLength + 2); // コマンドをデコードする byte[] byteImage = new byte[bodyLength + 4]; Array.Copy(buffer, byteImage, bodyLength + 4); recvCommand = CommandUtil.decodeCommand(byteImage); // Ackを受信した場合 if (recvCommand.Cmd == 'w' || recvCommand.Cmd == 'r') { // 状態異常時 if (sendStatus != SendStatus.AckWaiting) { ts.TraceInformation("AckWaiting以外でAckを受け取ったため無視します。"); } // 正常時 else { sendStatus = SendStatus.CommandProcessing; sendAckCommand = recvCommand.Clone(); } } // Ack以外のコマンドを受信した場合 else { // コマンド実行 execCommand(recvCommand); // Ackの返信 respondAck(recvCommand); } } catch { ts.TraceInformation("コマンド受信異常"); } // シーケンスを終了 recvStatus = RecvStatus.Ready; break; } }