Microsoft Robotics Developer Studio (RDS) 2008 R2 由四大核心組成:CCR (並發協調運行)、DSS (分散式軟體服務)、VPL (視覺化程式語言)、VSE (視覺化模擬環境)。本文聚焦 **VPL 服務開發**,以 **序列埠 (COM Port) 通訊服務** 為例,完整示範從服務契約定義、行為實作、配置檔、VPL 測試圖表的端到端流程。
ReceiveByte 通知WriteString 內建字元間延遲支援,相容無硬體 UART 的單晶片 (如 BasicStamp)
[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, ClearBuffersReadByte, ReadByteArray, ReadString (同步讀取)WriteByte, WriteByteArray, WriteString (同步寫入)ReceiveByte (內部非同步通知用,**不對外公開**)
protected override void Start()
{
InitializeState();
base.Start();
if (_state.OpenOnStart) OpenPort();
}
[ServiceHandler]
public void OpenHandler(Open open)
{
_state.Asynchronous = open.Body.Asynchronous;
if (OpenPort())
open.ResponsePort.Post(DefaultSubmitResponseType.Instance);
else
throw new Exception("Open Failed");
}
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;
}
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處理通知發送。
[ServiceHandler]
public void ReceiveByteHandler(ReceiveByte recv)
{
_state.LastByteReceived = recv.Body.Data;
if (_state.Asynchronous)
SendNotification(_submgrPort, recv); // 發送給訂閱者
recv.ResponsePort.Post(DefaultUpdateResponseType.Instance);
}
[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 排程器上恢復執行,**不阻塞執行緒池**。
false
false
1
57600
None
8
One
0
0
0
0
false
[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 圖表自動顯示圖示硬體需求:Null Modem 線纜連接兩個 COM 埠 (或 USB 轉序列埠 x2),一端執行 HyperTerminal,另一端執行 VPL 圖表。
Asynchronous = true,呼叫 OpenOpen 回應:成功 → 繼續;失敗 → 顯示錯誤ReceiveByte 通知 → 取得 Data → 呼叫 WriteByte 回傳

Asynchronous = false,呼叫 OpenReadString (阻塞至換行) → WriteString 回傳InterCharacterDelay = 500ms 觀察慢速發送效果
Projects\SerialPort)DssProjectMigration /b- .MSBuild serialport.sln 編譯 → 產生 Service DLL、Proxy DLL、Transform DLL 至 \bin\samples\config開始 → Microsoft Robotics → Visual Programming Language) 載入圖表測試本文完整展示一個 **生產級序列埠 VPL 服務** 的設計與實作:契約優先、CCR 非同步模式切換、跨執行緒 Port 郵寄、迭代器非阻塞延遲、配置檔驅動、VPL 友善屬性。此服務可作為機器人控制器、感測器介接、舊系統整合的通用通訊基石,展現 RDS 「服務導向、視覺化測試、非同步並行」的核心優勢。