首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Microsoft Robotics Developer Studio:編寫與測試支援序列埠通訊的 VPL 服務

     編輯:關於.NET

Microsoft Robotics Developer Studio (RDS) 2008 R2 由四大核心組成:CCR (並發協調運行)、DSS (分散式軟體服務)、VPL (視覺化程式語言)、VSE (視覺化模擬環境)。本文聚焦 **VPL 服務開發**,以 **序列埠 (COM Port) 通訊服務** 為例,完整示範從服務契約定義、行為實作、配置檔、VPL 測試圖表的端到端流程。

RDS 服務架構核心概念

  • SOA + REST + DSSP:服務透過代理通訊,訊息序列化為 XML,非直接呼叫。
  • 狀態 + 作業 + 通知:服務擁有內部狀態,外部透過作業 (Get/Set/Replace/Submit) 操作,狀態變更發送非同步通知給訂閱者。
  • VPL 即時可見:新建服務編譯後自動出現在 VPL 工具箱,無需撰寫測試宿主程式即可視覺化測試。

序列埠服務設計要點

  • 支援同步 (Read/Write 阻塞) 與非同步 (DataReceived 事件 + 通知) 兩種模式
  • 可配置參數:PortName、BaudRate、Parity、DataBits、StopBits、Read/Write Timeout、InterCharacterDelay
  • 非同步模式下每收到一個位元組發送 ReceiveByte 通知
  • WriteString 內建字元間延遲支援,相容無硬體 UART 的單晶片 (如 BasicStamp)

服務契約定義 (SerialPortTypes.cs)


[DataContract]
public class SerialPortState
{
    [DataMember] public bool OpenOnStart { get; set; }      // 啟動時自動開啟
    [DataMember] public bool Asynchronous { get; set; }       // 非同步模式
    [DataMember] public SerialPortConfig Config { get; set; } // 序列埠參數
    [DataMember] public byte LastByteReceived { get; set; }   // 最後收到位元組
    [DataMember] public bool IsOpen { get; set; }             // 連線狀態
}

[DataContract]
public class SerialPortConfig
{
    [DataMember] public int PortNumber { get; set; } = 1;
    [DataMember] public int BaudRate { get; set; } = 57600;
    [DataMember] public Parity Parity { get; set; } = Parity.None;
    [DataMember] public int DataBits { get; set; } = 8;
    [DataMember] public StopBits StopBits { get; set; } = StopBits.One;
    [DataMember] public int ReadTimeout { get; set; } = 0;
    [DataMember] public int WriteTimeout { get; set; } = 0;
    [DataMember] public int InterCharacterDelay { get; set; } = 0; // ms
}

public enum Parity { None, Odd, Even, Mark, Space }
public enum StopBits { One, Two, OnePointFive }

作業契約 (節錄)

  • Get, Subscribe (基礎)
  • SetConfig, Open, Close, ClearBuffers
  • ReadByte, ReadByteArray, ReadString (同步讀取)
  • WriteByte, WriteByteArray, WriteString (同步寫入)
  • ReceiveByte (內部非同步通知用,**不對外公開**)

服務行為實作 (SerialPort.cs 關鍵片段)

啟動與自動開啟


protected override void Start()
{
    InitializeState();
    base.Start();
    if (_state.OpenOnStart) OpenPort();
}

OpenHandler:支援同步/非同步模式切換


[ServiceHandler]
public void OpenHandler(Open open)
{
    _state.Asynchronous = open.Body.Asynchronous;
    if (OpenPort())
        open.ResponsePort.Post(DefaultSubmitResponseType.Instance);
    else
        throw new Exception("Open Failed");
}

OpenPort:非同步模式掛載 DataReceived 事件


private bool OpenPort()
{
    _serialPort = new System.IO.Ports.SerialPort(...);
    if (_state.Asynchronous)
    {
        _serialPort.ReceivedBytesThreshold = 1;
        _serialPort.DataReceived += DataReceivedHandler; // .NET 執行緒
    }
    _serialPort.Open();
    _state.IsOpen = true;
    return true;
}

DataReceivedHandler:跨執行緒轉發至 CCR Port


void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    while (_serialPort.BytesToRead > 0)
    {
        int data = _serialPort.ReadByte();
        var rb = new ReceiveByte { Body = { Data = (byte)data } };
        _mainPort.Post(rb); // 發送至服務主 Port
        Activate(Arbiter.Choice(rb.ResponsePort,
            success => { },
            fault => LogError("ReceiveByte failed")));
    }
}
關鍵:.NET 事件處理常式執行於 ThreadPool,**必須透過 _mainPort.Post 切換至 CCR 排程器**,再由 ReceiveByteHandler 處理通知發送。

ReceiveByteHandler:發送非同步通知


[ServiceHandler]
public void ReceiveByteHandler(ReceiveByte recv)
{
    _state.LastByteReceived = recv.Body.Data;
    if (_state.Asynchronous)
        SendNotification(_submgrPort, recv); // 發送給訂閱者
    recv.ResponsePort.Post(DefaultUpdateResponseType.Instance);
}

WriteStringHandler:迭代器實現字元間延遲 (非阻塞)


[ServiceHandler]
public virtual IEnumerator WriteStringHandler(WriteString write)
{
    if (!_state.IsOpen) throw new Exception("Port not open");
    if (write.Body.DataString == null) throw new Exception("Invalid Parameters");

    if (_state.Config.InterCharacterDelay > 0)
    {
        byte[] data = new byte[1];
        for (int i = 0; i < write.Body.DataString.Length; i++)
        {
            data[0] = (byte)write.Body.DataString[i];
            _serialPort.Write(data, 0, 1);
            yield return Timeout(_state.Config.InterCharacterDelay); // CCR 非阻塞等待
        }
        _serialPort.WriteLine("");
    }
    else
        _serialPort.WriteLine(write.Body.DataString);

    write.ResponsePort.Post(DefaultSubmitResponseType.Instance);
    yield break;
}
💡 yield return Timeout(...) 讓出執行緒,延遲結束後自動在 CCR 排程器上恢復執行,**不阻塞執行緒池**。

配置檔 (SerialPort.Config.xml)




  false
  false
  
    1
    57600
    None
    8
    One
    0
    0
    0
  
  0
  false

VPL 友善屬性:顯示名稱、描述、圖示、線上文件


[DisplayName("Serial Port Service")]
[Description("SerialPort service provides access to a Serial (COM) Port")]
[DssServiceDescription("https://www.promrds.com/SerialPort.htm")]
public class SerialPortService : DsspServiceBase { ... }
  • DisplayName:VPL 工具箱顯示名稱
  • Description:滑鼠懸停工具提示
  • DssServiceDescription:工具箱旁顯示資訊圖示 (藍色圓餅 + i),點擊開啟線上文件
  • 專案加入 SerialPortService.Image.png (32x32) 與 SerialPortService.Thumbnail.png (16x16),建置動作設為 **Embedded Resource**,VPL 圖表自動顯示圖示

VPL 測試程式:EchoAsynch 與 EchoSynch

硬體需求:Null Modem 線纜連接兩個 COM 埠 (或 USB 轉序列埠 x2),一端執行 HyperTerminal,另一端執行 VPL 圖表。

EchoAsynch (非同步模式)

  1. 設定 Asynchronous = true,呼叫 Open
  2. 檢查 Open 回應:成功 → 繼續;失敗 → 顯示錯誤
  3. 訂閱 ReceiveByte 通知 → 取得 Data → 呼叫 WriteByte 回傳
  4. 收到 CR (13) 時附加 LF (10) 換行,便於 HyperTerminal 顯示

VPL 非同步開啟序列埠

VPL EchoAsynch 完整圖表

EchoSynch (同步模式)

  1. Asynchronous = false,呼叫 Open
  2. 迴圈:ReadString (阻塞至換行) → WriteString 回傳
  3. 配置 InterCharacterDelay = 500ms 觀察慢速發送效果

VPL EchoSynch 圖表

建置與部署步驟

  1. 原始碼解壓至 RDS 安裝目錄下自建資料夾 (如 Projects\SerialPort)
  2. DSS 命令提示字元執行:DssProjectMigration /b- .
  3. MSBuild serialport.sln 編譯 → 產生 Service DLL、Proxy DLL、Transform DLL 至 \bin
  4. 複製 Manifest 與 Config 檔至 \samples\config
  5. 啟動 VPL (開始 → Microsoft Robotics → Visual Programming Language) 載入圖表測試

總結

本文完整展示一個 **生產級序列埠 VPL 服務** 的設計與實作:契約優先、CCR 非同步模式切換、跨執行緒 Port 郵寄、迭代器非阻塞延遲、配置檔驅動、VPL 友善屬性。此服務可作為機器人控制器、感測器介接、舊系統整合的通用通訊基石,展現 RDS 「服務導向、視覺化測試、非同步並行」的核心優勢。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved