Freigeben über


Dieser Artikel wurde maschinell übersetzt.

Robotik

Schreiben und Testen von VPL-Diensten für die serielle Kommunikation

Thomas Trevor

Microsoft Robotics Developer Studio (RDS) ist, wie Sie erwarten würden, eine Plattform für die Programmierung von Robotern. RDS ausgeliefert in 2006 und die neueste Version RDS 2008 R2 wurde im Juni 2009 veröffentlicht.

RDS besteht aus vier Hauptkomponenten: die Concurrency und Coordination Runtime (CCR) dezentrale Software Services (DSS), Visual Programming Language (VPL) und Visual Simulation Environment (VSE). Sara Morgan habe über VSE in der Ausgabe des Juni 2008 geschrieben.MSDN Magazine (MSDN.Microsoft.com/magazine/cc546547).

VPL, ist jedoch mehr zu diesem Artikel relevant sind. VPL ist eine Datenfluss-Sprache, d. Erstellen von Programmen h. durch Zeichnen von Diagrammen auf dem Bildschirm. Zur Laufzeit der Nachrichtenfluss von einem Block zum anderen im Diagramm, und dieser Datenfluss wird effektiv der Ausführungspfad des Programms. Da VPL auf CCR und DSS aufbaut, wird Dataflows asynchron (als Ergebnis von Benachrichtigungen von Diensten) auftreten können, und können auch parallel ausführen. Während VPL für Anfänger Programmierer konzipiert ist, können erfahrene Programmierern auch es für für Prototypen nützlich sein.

In diesem Artikel wird beschrieben, einen einfachen RDS-Dienst, der Sie senden und Empfangen von Daten mit einen seriellen Anschluss (auch bekannt als COM-Anschluss) ermöglicht wird. Im Beispielcode veranschaulicht einige der wichtigsten Konzepte schreiben wiederverwendbaren RDS Dienste beteiligt.

Erfahren Sie mehr über RDS und die Plattform zu downloaden, wechseln Sie zu microsoft.com/robotics. Das Paket umfasst eine nützliche Hilfedatei, die auch in msdn.microsoft.com/library/dd936006 verfügbar ist. Weitere Hilfe erhalten Sie durch die Buchung von Fragen zu den verschiedenen Robotics Diskussionsforen zu Social.msdn.Microsoft.com/Forums/en-us/Category/Robotics.

RDS-Dienste

RDS-Dienste sind mit CCR und DSS erstellt. Sie sind vom Konzept her ähnlich wie Webdienste, da RDS eine serviceorientierte Architektur (SOA) basierend auf einem Representational State Transfer (REST) Modell mithilfe von DSSP (dezentrale Software Services-Protokoll) für die Kommunikation zwischen Diensten hat. Bis alle diese Alphabet Suppe wading, was bedeutet dies ist, dass Sie direkt mit RDS Dienste kommunizieren nicht. Stattdessen senden Sie Nachrichten an einen Proxy, fungiert als die externe Schnittstelle für den Dienst (ein Webentwickler Ansatz mit vertraut ist). Dies bedeutet auch, dass Dienste, eine beliebige Stelle im Netzwerk verteilt werden können.

Über einen Proxyserver hat zwei Auswirkungen. Zunächst werden zwischen den Diensten gesendete Nachrichten vor der Übertragung serialisiert und deserialisiert am anderen Ende. XML ist das übliche Format für die übertragenen Daten. Zweitens der Proxy definiert einen Vertrag – effektiv den Satz von APIs, die andere Dienste zur Verfügung stehen.

Jeder Dienst hat einen internen Status, die Sie abrufen oder ändern, indem Sie Vorgänge auf den Dienst können. Diese umfassen das Senden einer Anforderungsnachricht und Warten auf eine Antwortnachricht in einem Prozess ähnelt, die von den meisten-Webdiensten verwendet.

Wenn ein Dienst Zustand ändert, können Sie Benachrichtigungen an Abonnenten senden. Dieses publish-and-subscribe-Ansatzes können RDS-Dienste sich von herkömmlichen Webdienste, da Benachrichtigungen asynchron an Abonnenten gesendet werden.

Wenn Sie einen neuen Dienst erstellen, können es wird automatisch in VPL sichtbar und beginnen sofort verwenden. Hierbei handelt es sich um eine der Hauptfunktionen von RDS und es macht testen und Erstellen von Prototypen sehr einfach – Sie Don ’t Harnesses Test in c# geschrieben haben, da VPL stattdessen verwendet werden können.

Steuern ein Roboter über Remotezugriff

Viele einfache erzieherischen Roboter haben 8 oder 16-Bit-Mikrocontrollern für Ihre integrierte Ins. Aber da RDS unter .NET Framework unter Windows ausgeführt wird, generiert er nicht Code, der direkt auf diese Roboter ausgeführt werden kann. Sie müssen von einem Remotestandort aus über eine Kommunikationsverbindung stattdessen gesteuert werden. (Die Alternative besteht darin, einen integrierten PC z. B. die 3DX MobileRobots Pioneer haben).

Da die Mehrzahl der Mikrocontrollern unterstützt serielle Anschlüsse, eine serielle Verbindung ist die nahe liegende Lösung. Nicht jedoch die Verknüpfung mit einem Kabel bereitstellen ist ideal – es der Roboter Mobilität einschränkt.

Als Alternative können Bluetooth Sie um eine drahtlose Verbindung zu erstellen, indem Sie eine serielle Bluetooth-Gerät auf der Roboter installieren. Einige Roboter, z. B. die LEGO NXT verfügen über integrierte Bluetooth. Andere, haben z. B. RoboticsConnection Stinger optionale Bluetooth-Module. Bluetooth ist eine gute Wahl, angesichts der Tatsache, dass es auf den meisten Laptops standard heutzutage ist. Selbst wenn Ihr PC mit Bluetooth-besitzt, finden Sie kostengünstig, zur Verfügung USB Bluetooth-Geräte.

Die gute Nachricht ist, dass Sie Don Kenntnisse über Bluetooth-Programmierung, da die Verbindung mit der Roboter als einen virtuellen seriellen Anschluss angezeigt wird. Sie können denselben Code verwenden, wie ein physischen Kabel die serielle Verbindung bereitgestellt wurden. Der einzige Unterschied besteht darin, dass Sie zum Einrichten der Verbindungsaufbau zwischen dem PC und das Bluetooth-Gerät auf der Roboter so ein virtueller COM-Anschluss erstellt wird.

Einige Roboter Controller-Karten haben Firmware, die mit eine einfachen Befehlssprache Befehle annehmen kann. Das Serialisierungsprogramm von RoboticsConnection (die den Namen aus der Verwendung eines seriellen erhält), können Sie z. B. Befehle zum Domänencontroller über ein Terminalprogramm wie HyperTerminal eingeben. Befehle sind alle lesbaren und Sie jeweils durch Drücken von beendenGeben Sie ein.

Wenn Sie Ihr eigenes Protokoll für die Verwendung mit einem Roboter entwerfen, müssen Sie einige Entscheidungen treffen. Zunächst müssen Sie entscheiden, ob Sie binäre Daten gesendet werden. Konvertieren von Binärwerten in Hexadezimal- oder Dezimalformat für die Übertragung benötigt mehr Bandbreite und die Verarbeitung für die integrierte CPU-Verwaltungsaufwand erhöht. Andererseits, Lesen von Nachrichten, die viel einfacher macht, und es wird keine ungewöhnliches Verhalten aufgrund von misinterpreted Steuerzeichen auftreten.

Die nächste Frage ist, ob Pakete fester Länge oder ein flexibler Format mit variabler Länge verwendet werden soll. Fester Länge ist einfacher zu analysieren und funktioniert am besten mit Hexadezimalwerten.

Berücksichtigen Sie auch, ob Sie eine Prüfsumme verwenden. Für die Berechnung von Kontrollkästchen Ziffern Computer-mit-Computer-Kommunikation ist einfach. Wenn Sie Ihr Roboter zu testen, indem Sie Befehle manuell eingeben möchten, ruft die Kontrollkästchen Stellen herauszufinden sehr schwierig. Bei der Verwendung von Prüfsummen sichern typically sendet der Empfänger eine Bestätigung (ACK) oder eine negative Bestätigung (NAK) abhängig, ob der Befehl erfolgreich oder nicht über stammt. Die Entscheidung über die Verwendung einer Prüfsumme kommt wirklich um die Zuverlässigkeit der Verbindung.

SerialPort-Dienst

Sollte es offensichtlich durch jetzt warum ein seriellen Anschluss Dienst nützlich wäre. RDS-Paket, enthalten nicht jedoch einen solcher Dienst, obwohl viele der Beispiele Roboter serielle Kommunikationsverbindungen verwendet werden. Wenn Sie den RDS-Beispielcode zu untersuchen, werden Sie feststellen, dass jedes Beispiel den seriellen Anschluss anders behandelt. Dieser Artikel beschreibt eine Methode mit einen seriellen Anschluss. Es ist nicht die einzige Möglichkeit, dies und nicht unbedingt die beste Möglichkeit.

Bevor eine weitere, stellen Sie sicher, dass gedownloadet und installiert RDS. Der Download für diesen Artikel enthält den Quellcode des Dienstes SerialPort. Entzippen Sie ihn in einen Ordner unter dem Installationsverzeichnis von RDS (auch bekannt als der Bereitstellungspunkt). Beachten Sie, dass Ihr Code beibehalten werden sollte getrennt vom Beispielordner das im Lieferumfang enthaltene RDS so, Don ’t Mischen von Code mit dem Microsoft-Code. Darüber hinaus empfehle ich platzieren Code unter der Bereitstellungspunkt RDS und nicht an anderer Stelle auf der Festplatte, da es vereinfacht die Entwicklung. Ich habe einen Ordner Projekte, in denen ich meine eigenen Code in Unterordnern beibehalten sichern zu erleichtern.

Die wichtigsten Dateien im Quellcode SerialPort sind SerialPort.cs, SerialPortTypes.cs und SerialPort.manifest.xml.

SerialPort.cs enthält die Implementierung des Dienstes oder das Verhalten. Es besteht aus der Dienstklasse selbst, die die Operation Handler enthält, sowie alle erforderlichen unterstützenden Methoden und Variablen.

SerialPortTypes.cs enthält die Definitionen der den Status des Dienstes, Vorgangstypen und Nachrichtentypen. Wirksam, es wird beschrieben, die Schnittstelle, um den Dienst, und sollte nicht ausführbaren Code enthalten. Dies ist ein wichtiger Punkt zu einem Servicevertrag – nur die Definition eines Daten.

SerialPort.manifest.xml wird aufgerufen, das Manifest und beschreibt, wie Dienste kombiniert werden, oder, für die Ausführung einer Anwendung orchestriert. Diese Datei dient als Eingabe für das DssHost-Dienstprogramm, das einen DSS-Knoten erstellt, dem Dienste ausgeführt. In diesem Fall wird das Manifest nur relativ nutzlos ist SerialPort-Dienst ausgeführt. Eine nützliche Manifest würde auch andere Dienste angeben, die vom SerialPort-Dienst zum Herstellen von Verbindungen angewiesen sind.

Bevor Sie mit den SerialPort-Dienst, führen Sie das DssProjectMigration-Tool aus, und kompilieren Sie den Dienst neu. Öffnen Sie eine Eingabeaufforderung DSS (Suchen Sie im Startmenü unter RDS), und stellen Sie sicher, dass die Pfade eingerichtet sind, so dass Sie Dateien im Ordner "\bin" ausführen können. Ändern Sie in das Verzeichnis, in dem Sie den Code Entzippen, und geben Sie den folgenden Befehl ein:

Dssprojectmigration /b- .

Die /b-option bedeutet Don ’t eine Sicherungskopie erstellen und der Punkt (.) bezieht sich auf das aktuelle Verzeichnis.

Kompilieren Sie den Dienst in Visual Studio oder über die Befehlszeile tun, indem Sie eingeben können:

Msbuild serialport.sln

Kompilieren den Dienst generiert der Dienst-DLL, eine Proxy-DLL und eine Transformation DLL (das Datentypen zwischen dem Dienst-DLL und der Proxy). Diese werden alle in den Ordner "\bin" unter dem RDS-Bereitstellungspunkt platziert. Sie sollten auch Zusammenhalten Manifest und Config-Dateien durch Kopieren in den Ordner "\Beispiele\config", (obwohl dies nicht wichtig ist).

Der Servicevertrag

Jeder Dienst hat eine eindeutige Vertrag-Kennung, die in der Types.cs-Datei deklariert ist und sieht wie ein URL. Beachten Sie jedoch, dass es keine Bedeutung, im Web hat, und mithilfe einer URL-Format-ID einfach eine bequeme Möglichkeit zur Eindeutigkeit zu gewährleisten ist, indem ermöglicht Organisationen das Erstellen eigener Namespaces. (Für Ihre Projekte müssen Sie einen anderen Namespace als microsoft.com/robotics verwenden.) SerialPortTypes.cs enthält die folgende Definition:

public sealed class Contract {
  [DataMember]
  public const string Identifier = "http://www.promrds.com/contracts/2009/12/serialport.html";
}

Ein Servicevertrag beinhaltet auch den Status und die Vorgänge, die über die Eigenschaften zu definieren, die andere Dienste bearbeiten können und wie. SerialPortState (siehe Abbildung 1) enthält den seriellen Anschluss-Konfiguration, einige Parameter für Timeoutwerte und das letzte Byte, die beim Betrieb asynchron empfangen.

Abbildung 1 SerialPortState

[DataContract]
public class SerialPortState {
  private bool _openOnStart;
  private bool _asynchronous;
  private SerialPortConfig _config;
  private byte _lastByteReceived;
  private bool _isOpen;

  // Open the COM port when the service starts
  // Must be set in config file
  [DataMember]
  public bool OpenOnStart {
    get { return _openOnStart; }
    set { _openOnStart = value; }
  }

  // Operate in Asynchronous mode 
  [DataMember]
  public bool Asynchronous {
    get { return _asynchronous; }
    set { _asynchronous = value; }
  }

  // Configuration parameters for the serial port
  [DataMember]
  public SerialPortConfig Config {
    get { return _config; }
    set { _config = value; }
  }

  // Last byte received from the serial port
  [DataMember]
  public byte LastByteReceived {
    get { return _lastByteReceived; }
     set { _lastByteReceived = value; }
  }

  // Indicates if the port is currently open
  [DataMember]
  public bool IsOpen {
    get { return _isOpen; }
    set { _isOpen = value; }
  }
}

Sie können eigene Datentypen für die Verwendung in den Zustand und eine Meldung Typen definieren. In diesem Dienst ist eine SerialPortConfig-Klasse. Um es in der Proxy sichtbar zu machen, muss er öffentliche und mit dem [DataContract]-Attribut gekennzeichnet sein. Jede Eigenschaft in der Klasse muss als öffentlich deklariert werden und auch mit dem Attribut [DataMember] markiert. Wenn dies nicht ist, wird die Eigenschaft nicht zugänglich.

Sie können auch öffentliche Enumerationen verfügbar machen – auf diese Weise andere Programmierer magische Zahlen im Code verwenden, die Ihr Dienst verfügen. Es gilt als guter Programmierstil, zu, da Datentyp überprüft werden können.

Beim Entwerfen eines Dienstes müssen Sie auch entscheiden, wie andere Dienste mit ihm interagieren. Dieser Dienst SerialPort unterstützt die folgenden Operationen in logischen Gruppen unten aufgeführten:

  • Erhalten, abonnieren
  • ReceiveByte
  • SetConfig "," Offen "," Schließen "," ClearBuffers
  • ReadByte, ReadByteArray, ReadString
  • WriteByte, WriteByteArray, WriteString

Beachten Sie, dass der ReceiveByte-Vorgang für die interne Verwendung durch den Dienst selbst ist und sollte nicht von anderen Diensten verwendet werden. Auf dieses Thema wird zu einem späteren Zeitpunkt weiter eingegangen.

Die Read- und Write-Vorgänge sind alle synchron, bis der Vorgang abgeschlossen ist, reagiert der Dienst nicht. Wenn Sie den seriellen Anschluss im asynchronen Modus (siehe unten) öffnen, senden Sie der Dienst eine Benachrichtigung ReceiveByte für jedes Byte empfangen, und verwenden Sie die Lesevorgänge nicht. Die Schreibvorgänge sind jedoch immer synchron.

Jede Operation hat eine Anforderung des Nachrichtentyps und einen Antworttyp für die Nachricht. Möglicherweise einige dieser Eigenschaften und andere ist leer – der Datentyp selbst ist ausreichend, um die entsprechende Nachricht zu übermitteln.

Service-Verhalten

Wie bereits erwähnt, ist der ausführbare Code des Dienstes in SerialPort.cs. Alle Dienste werden von DsspServiceBase, abgeleitet, die eine Reihe von Hilfsmethoden und Eigenschaften bereitstellt. Wenn ein Dienst gestartet wird, wird die Start-Methode aufgerufen:

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

Start kümmert initialisiert den Zustand (falls erforderlich), und öffnen den seriellen Anschluss automatisch, wenn OpenOnStart in der Config-Datei (siehe unten) angegeben wurde.

Jede Operation, die von einem Dienst unterstützt, muss einen Dienst-Handler verfügen. Aber einige Operationen, z. B. ablegen und abrufen, durch die Infrastruktur (es sei denn, Sie das Standardverhalten zu überschreiben möchten) behandelt werden.

Die OpenHandler zeigt einen sehr einfachen Ereignishandler:

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

Dieser Ereignishandler ruft OpenPort, eine interne Methode. Wenn dies erfolgreich ist, wird eine Antwort zurückgesendet. Da keine Informationen zurückgegeben werden, ist dies nur eine Standardantwort, die vom DSS bereitgestellt.

Schlägt das Öffnen, wird eine Ausnahme ausgelöst. DSS fängt die Ausnahme ab und konvertiert es zu einem Fehler, die wieder als die Antwort gesendet wird. Obwohl nicht sofort offensichtlich, wenn eine Ausnahme, in OpenPort auftritt, wird auch Blase einrichten und einen Fault zurückzugeben.

Besteht keine Notwendigkeit, Erläutern Sie alle der OpenPort-Methode, ein Punkt ist jedoch wichtig – Sie können den seriellen Anschluss für die synchrone oder asynchrone Operation öffnen. Im synchronen Modus von alle Lese- und Schreibanforderungen, die vor der Rückgabe einer Antwort abgeschlossen. Wenn Sie im asynchronen Modus öffnen, werden Benachrichtigungen für jedes Zeichen empfangen gesendet. Damit diese funktioniert, legt der Code einen konventionellen Ereignishandler:

if (_state.Asynchronous) {
  // Set up an Event Handler for received characters
  sp.ReceivedBytesThreshold = 1;
  sp.DataReceived += new SerialDataReceivedEventHandler(
    DataReceivedHandler);
}

Der Ereignishandler ist in dargestellt.Abbildung 2. Dieser Handler in einem Thread .NET ausgeführt wird. Aber für die Zusammenarbeit mit DSS es muss umgestellt werden zu einem CCR-Thread, sodass der Code eine ReceiveByte-Anforderung an den Anschluss des Dienstes Hauptoperationen bucht. Nach dem Buchen einer Anforderung, sollte der Code die Antwort erhalten, andernfalls wird es nicht der gesamte reservierte Speicher freigegeben. Dies ist der Zweck der Arbiter.Choice, die C#-Kurznotation für anonyme Delegaten, verwendet um die zwei möglichen Antworten zu behandeln. Ein Activate ist erforderlich, um die Auswahl Empfänger in der aktiven Warteschlange platziert. Nur ein Fehler ist in diesem Fall relevant, und ein erfolgreiches Ergebnis hat keine Auswirkungen.

Abbildung 2 Ereignishandler

void DataReceivedHandler(object sender, 
  SerialDataReceivedEventArgs e) {

  int data;
  while (sp.BytesToRead > 0) {
    // Read a byte - this will return immediately because
    // we know that there is data available
    data = sp.ReadByte();
    // Post the byte to our own main port so that
    // notifications will be sent out
    ReceiveByte rb = new ReceiveByte();
    rb.Body.Data = (byte)data;
    _mainPort.Post(rb);
    Activate(Arbiter.Choice(rb.ResponsePort,
      success => { },
      fault => { LogError("ReceiveByte failed"); }
      ));
  }
}

Der ReceiveByte-Handler wird als Nächstes ausgeführt werden, um das neue Zeichen verarbeiten:

[ServiceHandler]
public void ReceiveByteHandler(ReceiveByte recv) {
  _state.LastByteReceived = recv.Body.Data;
  // Send a notification, but only if in asynch mode
  if (_state.Asynchronous)
    SendNotification(_submgrPort, recv);
  recv.ResponsePort.Post(DefaultUpdateResponseType.Instance);
}

Das Attribut [Diensthandler] kann DSS Handler an den Anschluss Vorgänge während der Dienstinitialisierung zu verknüpfen. Der Handler sendet eine Benachrichtigung an den Abonnenten und dann bucht wieder eine Antwort, die besagt, dass der Vorgang abgeschlossen ist. (Dienste, die Benachrichtigungen erhalten möchten, müssen eine Subscribe-Operation für den SerialPort-Dienst zu senden).

Service Handler für die andere lesen, und Schreibvorgänge sind relativ selbsterklärend. Die WriteStringHandler (siehe Abbildung 3) enthält eine kleine Falten jedoch – Sie können eine kleine Verzögerung zwischen dem Senden von Zeichen einzufügen. Dies eignet sich zum langsamere Mikrocontrollern, die möglicherweise nicht bewältigen können, wenn die Daten bei voller Geschwindigkeit, Geräte wie die BasicStamp especially gesendet werden, die banging-bit und Don ’t haben eine Hardware-Universal Asynchronous Receiver/Transmitter (UART), damit Sie eine serielle e/a-in-Software ausführen.

Abbildung 3 WriteStringHandler

[ServiceHandler]
public virtual IEnumerator<ITask> WriteStringHandler(
  WriteString write) {

  if (!_state.IsOpen) {
    throw (new Exception("Port not open"));
  }

  // Check the parameters - An empty string is valid, but not null
  if (write.Body.DataString == null)
    throw (new Exception("Invalid Parameters"));

  // NOTE: This might hang forever if the comms link is broken
  // and you have not set a timeout. On the other hand, if there
  // is a timeout then an exception will be raised which is
  // handled automatically by DSS and returned as a Fault.
  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];
      sp.Write(data, 0, 1);
      yield return Timeout(_state.Config.InterCharacterDelay);
    }
    sp.WriteLine("");
  }
  else
    sp.WriteLine(write.Body.DataString);

  // Send back an acknowledgement now that the data is sent
  write.ResponsePort.Post(DefaultSubmitResponseType.Instance);
  yield break;
}

Ein weiterer Punkt über diesen Handler ist, dass ein Iterator. Beachten Sie die Deklaration der Methode als IEnumerator <itask>und die Tatsache, dass es sich um Rendite verwendet yield Break und zurückgeben. Dieses Feature von C#-Sprache ermöglicht CCR, um Vorgänge zu unterbrechen, ohne einen Thread zu blockieren. Wenn der Yield return ausgeführt wird, ist der Thread Ausführen der Methode an den Pool zurückgegeben. Sobald das Zeitlimit abgeschlossen hat, sendet es wieder eine Nachricht, bei dem die Ausführung fortgesetzt werden soll, obwohl Sie möglicherweise auf einem anderen Thread.

Konfigurieren des Dienstes

Eine Konfigurationsdatei ist eine XML-serialisierte Version der den Status des Dienstes, der während der Dienstinitialisierung geladen wird. Es ist ratsam, eine Config-Datei unterstützt werden, da es Ihnen ermöglicht, die das Verhalten des Dienstes ohne Neukompilierung zu ändern. Dies ist besonders wichtig für die COM-Anschlussnummer festlegen.

Wenn Sie die Status-Instanz (in SerialPort.cs) deklarieren, können Sie den Namen der Datei in den Dienst angeben:

[ServiceState]
// Add an initial state partner to read the config file
[InitialStatePartner(Optional = true, 
  ServiceUri = "SerialPort.Config.xml")]
SerialPortState _state = new SerialPortState();

In diesem Fall haben wir die Config als optional deklariert werden; andernfalls wird nicht der Dienst gestartet, wenn die Config-Datei fehlt. Andererseits, daher müssen Sie den Zustand in den Dienst Start-Methode überprüfen und auf einige sinnvolle Standardwerte initialisieren, falls erforderlich.

Da kein Pfad für die ServiceUri angegeben ist, DSS geht davon aus, dass die Datei in demselben Ordner wie das Manifest, das zum Starten des Dienstes verwendet wird. Abbildung 4 zeigt den Inhalt einer typischen Config-Datei.

Abbildung 4 Die Konfigurationsdatei für SerialPortState

<?xml version="1.0" encoding="utf-8"?>
<SerialPortState 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns=http://www.promrds.com/contracts/2009/12/serialport.html
  >
  <OpenOnStart>false</OpenOnStart>
  <Asynchronous>false</Asynchronous>
  <Config>
    <PortNumber>1</PortNumber>
    <BaudRate>57600</BaudRate>
    <Parity>None</Parity>
    <DataBits>8</DataBits>
    <StopBits>One</StopBits>
    <ReadTimeout>0</ReadTimeout>
    <WriteTimeout>0</WriteTimeout>
    <InterCharacterDelay>0</InterCharacterDelay>
  </Config>
  <LastByteReceived>0</LastByteReceived>
  <IsOpen>false</IsOpen>
</SerialPortState>

Beachten Sie, dass diese Config-Datei nicht den Dienst, öffnen den COM-Anschluss automatisch, anfordert so Sie eine Open-Anforderung zu senden müssen.

Wenn Sie Ihren Dienst für ein professionelles Erscheinungsbild haben möchten, müssen Sie auf Details, wie z. B. die Dienstbeschreibung und Symbole achten. Selbst wenn Don VPL selbst verwendet werden soll, ist es ratsam, Ihren Dienst in VPL testen, und machen es VPL-freundliche, so dass andere Personen es problemlos verwenden können.

Sie können die Dienstklasse mit zwei Attributen ergänzen, die den Dienst zu beschreiben:

[DisplayName("Serial Port Service")]
[Description("SerialPort service provides access to a Serial (COM) Port")]

Das erste Attribut zeigt, wie der Name des Dienstes in der Liste der VPL-Dienste (siehe Abbildung 5), und das zweite Attribut wird als QuickInfo angezeigt, wenn Sie über den Namen des Dienstes in der Liste Maus.


Abbildung 5 VPL Dienstleistungsliste

Wenn Sie eine Website haben, und Dokumentieren Sie Ihre online-Dienste werden soll, können Sie auf die Dienstklasse, geben Sie den Hyperlink ein anderes Attribut anfügen:

[DssServiceDescription("http://www.promrds.com/SerialPort.htm")]

VPL dieses Attribut erkennt, fügt einen kleinen Informationssymbol (weiß-“ i ” auf einem blauen CD) neben dem Dienst hinzu, in der Liste der Dienste.

Wenn Sie Symbole zu Ihrem Dienst, was problemlos möglich hinzufügen, werden Sie in VPL-Diagramme und der Liste der Dienste angezeigt. Beachten Sie das kleine Symbol, das eine Miniaturansicht, neben den Namen des Dienstes in aufgerufenAbbildung 5Abbildung 6 veranschaulicht die größere Version des das-Symbol, in dem Block angezeigt wird, die in Diagrammen VPL angezeigt wird.


Abbildung 6 Dienst blockieren

Wenn Sie diese Bilder zu einem Projekt hinzufügen, stellen Sie sicher, dass Sie die Dateieigenschaften ändern, so dass die Buildaktion auf eingebettete Ressource festgelegt ist. PNG ist das bevorzugte Format, da er auf einen alpha-Kanal unterstützt. Auf diese Weise können Sie ein Symbol mit einem transparenten Hintergrund zu erstellen, indem Sie den Alphawert für die Hintergrundfarbe auf 0 (null) festlegen.

Das Symbolbild Dienst sollte 32 x 32 Pixel und die Miniaturansicht 16 x 16 sein. Die Dateinamen der Bilder müssen mit dem Klassennamen des Dienstes in diesem Fall SerialPortService beginnen. Daher versucht ich die Dateinamen für mein Beispiel SerialPortService.Image.png und SerialPortService.Thumbnail.png.

Verwenden des Diensts

Der Dienst ist sehr flexibel. Sie können die seriellen Anschluss-Konfiguration in einer Config-Datei (Dies ist die gängigste Methode) oder durch Senden einer Anforderung SetConfig angeben. Nachdem Sie die Konfiguration festgelegt haben, können Sie die Open-Operation aufrufen. Der Einfachheit halber wird ein Flag in der Config-Datei bewirken, dass der Dienst den Port automatisch beim Start öffnen. Wenn der Anschluss bereits geöffnet ist, wird der Aufruf von Open zuerst schließen, und öffnen Sie ihn erneut.

Sie müssen entscheiden, wie Sie den Dienst verwenden möchten: synchron oder asynchron. Beim synchronen Betrieb jeder Lese- oder Schreibanforderung wartet, bis der Vorgang abgeschlossen, ist bevor Sie wieder eine Antwort zu senden. Hinsichtlich der VPL ist dies ein einfacher Ansatz, da in SerialPort-Block, in dem Diagramm der Nachrichtenfluss angehalten wird. Beachten Sie, dass asynchrone Operation nicht vollständig asynchronen – schreiben Sie Operationen weiterhin synchron ausgeführt. Aber jedes neue Byte empfangen als eine Benachrichtigung an die Abonnenten gesendet wird.

Theoretisch sollte jedem Vorgang Zustand ändern in einem Dienst verursachen, eine Benachrichtigung gesendet werden, sodass Abonnenten Ihre eigene zwischengespeicherte Version der den Status des Dienstes beibehalten können. Dies bedeutet, dass alle Vorgänge auf der Grundlage des DSSP zu ersetzen, Update, INSERT, DELETE und Upsert Operationen eine entsprechende Benachrichtigung senden soll. Allerdings Entwickler häufig schnell wiedergeben und mit dieser Anforderung gehen verloren.

Der Einfachheit halber sendet der SerialPort-Dienst nur Benachrichtigungen über den Typ der ReceiveByte-Operation im asynchronen Modus. Open, Close, und SetConfig Operationen verursachen auch Benachrichtigungen gesendet werden.

Da die Read- und Write-Vorgänge nicht den Status zu ändern, werden Sie aus der DSSP Submit-Vorgang als Unterklasse definiert. Natürlich haben Sie eine Nebenwirkung, die zum Empfangen und Senden von Daten über die serielle Verbindung ist.

Testen mit VPL

Der Download für diesen Artikel enthält zwei VPL Beispielprogramme, EchoAsynch und EchoSynch, wie den Dienst im asynchronen Modus (über Benachrichtigungen) und synchronen Modus verwendet werden. VPL-Beispiele verwenden Config-Dateien, um die anfängliche Parameter für COM-Anschluss, einschließlich der Anschlussnummer (die in der Config-Dateien auf 21 festgelegt und muss geändert werden, damit der COM-Anschlussadresse des Computers entsprechen) festlegen.

Beachten Sie, um den Dienst testen Sie ein Nullmodemkabel und entweder zwei Computern mit seriellen Ports oder zwei Ports auf demselben Computer benötigen. USB-seriell-Geräte sind verfügbar, daher ist es durchaus möglich, mehrere serielle Anschlüsse auf einem einzigen PC haben. Wenn Sie Ihre COM-Anschlüsse miteinander verbunden haben, führen Sie eine Terminalemulation wie HyperTerminal und Herstellen einer Verbindung mit einem der COM-Anschlüsse. Durch Ausführen des EchoAsynch VPL-Programms auf den seriellen Anschluss starten. (Sie können im Startmenü unter RDS VPL finden). Wenn Sie in das Fenster Terminalemulator eingeben, sollte die Zeichen zurückgegeben angezeigt werden.

VPL können Config-Dateien erstellt werden. Klicken Sie auf einen SerialPort-Dienst-Block im Diagramm, und suchen Sie im Eigenschaftenpanel. Sie sollten etwa angezeigt Abbildung 7. Stellen Sie sicher, dass die Anschlussnummer für den Computer ordnungsgemäß eingerichtet ist. (Dies muss es sich um den seriellen Anschluss, nicht die von Ihnen in der Terminalemulation geöffnet). Sie werden bemerken, dass der Parität und Stoppbits Dropdown-Listen sind. Die Einträge in diesen Listen kommen direkt von Enumerationen, die in SerialPortTypes.cs definiert.


Abbildung 7 Konfiguration des Dienstes am seriellen Anschluss

Dies ist ein Ort, in dem XML-Dokumentkommentare in nützlich. Wenn Sie über eine Config-Parameter mit dem Mauszeiger bewegen, wird eine QuickInfo mit den entsprechenden Kommentar für jedes Element Zustand angezeigt.

Beim Ausführen des EchoAsynch VPL-Programms im ersten Teil des Programms in Abbildung 8 wird den seriellen Anschluss im asynchronen Modus geöffnet.


Abbildung 8 Öffnen den seriellen Anschluss im asynchronen Modus

Öffnen schlägt fehl, wenn Sie ungültige Werte in der Konfigurationsdatei, z. B. eine ungültige Baudrate eingegeben haben. (Es kann auch fehlschlagen, wenn der COM-Anschluss verwendet wird, der Port ist nicht vorhanden oder Sie verfügen nicht über die entsprechende Berechtigungen). Dies ist der Grund, warum das Programm nach einem Fehler sucht und zeigt es an.

Der Rest des Programms (siehe Abbildung 9) nur gibt jedes Zeichen empfangen. Dies geschieht durch die Zeichen aus ReceiveByte Benachrichtigungen und senden Sie wieder mit WriteByte.

Um die Ausgabe übersichtlicher zu gestalten, ein Wagenrücklauf Zeichen (ASCII 13, decimal) hat einen Zeilenvorschub (10) angefügt, so dass der Cursor zur nächsten Zeile im Fenster Terminalemulator verschoben wird. Beachten Sie, dass alle von der SerialPortService in der blockiert Abbildung 9 Diagramm finden Sie in der gleichen Instanz des Dienstes.


Abbildung 9 EchoAsynch-Programm

Das Programm EchoSynch VPL (siehe Abbildung 10) verwendet den synchronen Betriebsmodus – es keine Benachrichtigungen verwenden. (In der Tat werden Benachrichtigungen nie im synchronen Modus gesendet).


Abbildung 10 Das EchoSynch-Programm

Im Gegensatz zum vorherigen Programm verwendet dieses ReadString und WriteString Echo Daten. Diese Operationen ausführen, ähnlich wie ReadByteArray und WriteByteArray bei Funktionen, Zeichenfolgen sind jedoch einfacher, als Bytearrays in VPL behandeln.

Die Zeichenfolgenoperationen verwenden eine Zeilenvorschub (oder Zeilenvorschub) Zeichen als ein End-of-Line-Marker. Daher werden ReadString abgeschlossen ist, wenn Sie nicht, wenn Sie die Taste ENTER betätigen, Zeilenvorschub (STRG-J) drücken. Dies kann beim ersten verwirrend werden Sie das Programm, das eine Terminalemulation testen, da Sie möglicherweise gefragt, warum nichts Echo ist. WriteString Fügt ein Wagenrücklauf und Zeilenvorschub in die Ausgabe, so dass jede Zeichenfolge in einer separaten Zeile angezeigt wird.

Beachten Sie, dass die Config-Datei für EchoSynch einer InterCharacterDelay 500ms. Dies hat zur Folge, dass der Zeichenfolgen sehr langsam gesendet werden. Sie können versuchen, diesen Wert ändern.

Thomas Trevor Bereich, ist der Programmmanager für Robotics Developer Studio an Microsoft. Er ist Mitautor, mit der Kyle-Johns von “ Professional Robotics Developer Studio ” (Wrox, 2008). Steht Beispielcode aus dem Adressbuchpromrds.com.

* *

Dank an die folgenden technischen Experten für die Überprüfung dieses Artikels:Kyle Johns