Este artigo foi traduzido por máquina.

Robótica

Escrevendo e testando serviços VPL para comunicação serial

José Trevor

Microsoft Robotics Developer Studio (RDS) é, conforme esperado, uma plataforma de programação de robots. RDS fornecidos pela primeira vez em 2006 e a versão mais recente, RDS 2008 R2, foi lançada em junho de 2009.

RDS consiste em quatro componentes principal: Concurrency and Coordination Runtime (CCR) Decentralized Software Services (DSS), linguagem de programação Visual (VPL) e ambiente de simulação visual (VSE). Sara Morgan escreveu sobre o VSE na edição de junho de 2008 da MSDN Magazine (MSDN.Microsoft.com/magazine/cc546547).

VPL, no entanto, é mais pertinente a este artigo. VPL é uma linguagem de fluxo de dados, o que significa que você criar programas desenhar diagramas na tela. Em tempo de execução, mensagens flua de um bloco para outra no diagrama, e este fluxo de dados é efetivamente o caminho de execução do programa. Como VPL é incorporada na parte superior de CCR e DSS, dataflows podem ocorrer assincronicamente (como resultado de notificações de serviços) e também pode executar em paralelo. Enquanto o VPL se destina a programadores iniciantes, experientes codificadores também poderá encontrá-lo útil para criação de protótipos.

Este artigo descreve um serviço RDS simples que permite enviar e receber dados usando uma porta serial (também conhecido como uma porta COM). O código de exemplo ilustra alguns dos principais conceitos envolvidos na escrita serviços reutilizáveis do RDS.

Para saber mais sobre RDS e baixe a plataforma, vá para microsoft.com/robotics. O pacote inclui um arquivo de ajuda úteis, que também está disponível em msdn.microsoft.com/library/dd936006. Você pode obter ajuda adicional, postando perguntas vários fóruns de discussão Robotics em social.msdn.Microsoft.com/Forums/en-US/category/Robotics.

Serviços RDS

Serviços RDS são criados usando CCR e DSS. Eles são conceitualmente semelhantes aos serviços da Web porque o RDS tem uma arquitetura orientada a serviços (SOA) baseada em um modelo (REPRESENTATIONAL State Transfer) usando o DSSP (Decentralized Software Services Protocol) para comunicação entre serviços. Wading através de todo esse soup alfabeto, isso significa que Don falar com diretamente a serviços do RDS. Em vez disso, você envia mensagens para um proxy, que atua como a interface externa para o serviço (desenvolvedores de Web uma abordagem estará familiarizado com). Isso também significa serviços podem ser distribuídos em qualquer lugar na rede.

Usando um proxy tem dois efeitos. Primeiro, as mensagens enviadas entre os serviços são serializadas antes da transmissão e desserializadas na outra extremidade. XML é o formato usual para os dados sendo transmitidos. Segundo, o proxy define um contrato — efetivamente o conjunto de APIs que estão expostos a outros serviços.

Cada serviço tem um estado interno, que você pode recuperar ou modificar operações no serviço. Esses envolvem enviando uma mensagem de solicitação e aguardando uma mensagem de resposta em um processo semelhante àquele utilizado pela maioria dos serviços da Web.

Quando alterado do estado do serviço, ele pode enviar notificações aos assinantes. Essa abordagem de publicação e assinatura torna RDS serviços diferentes dos Web services tradicionais como mensagens de notificação são enviadas assincronamente aos assinantes.

Quando você cria um novo serviço, ele automaticamente se torna visível no VPL e você pode começar a usá-lo imediatamente. Este é um dos principais recursos do RDS, e torna testes e desenvolvimento de protótipos muito fácil — você Don precise escrever testes aproveita translation from VPE for Csharp, porque você pode usar VPL em vez disso.

Controlar remotamente uma robot

Vários robôs educacionais simples têm Microcontroladores 8 ou 16 bits para seu cérebro integrado. Mas como RDS é executado sob o .NET Framework no Windows, ele não gera código que pode ser executado diretamente nesses robôs. Eles devem ser controlados remotamente por meio de um link de comunicações, em vez disso. (A alternativa é ter um PC na placa como 3DX MobileRobots Pioneer).

Desde que a maioria dos Microcontroladores suporta portas seriais, uma conexão serial é a solução óbvia. No entanto, fornecer o vínculo usando um cabo não ideal — ele limita mobilidade do robô.

Como alternativa, você pode usar o Bluetooth para criar uma conexão sem fio instalando um dispositivo serial para Bluetooth no robô. Alguns robôs, tais como NXT LEGO, vêm com Bluetooth incorporada. Outros, como RoboticsConnection Stinger, têm módulos Bluetooth opcionais. Bluetooth é uma boa opção, é padrão na maioria dos laptops hoje em dia. Mesmo que seu computador não tenha o Bluetooth, você encontrará os dispositivos USB Bluetooth baratos e prontamente disponíveis.

A boa notícia é que você Don precisa saber nada sobre programação Bluetooth porque a conexão com o robô aparecerá como uma porta serial virtual. Você pode usar o mesmo código, como você faria se um cabo físico foram fornecendo a conexão serial. A única diferença é que você precisa estabelecer uma combinação entre o seu computador e o dispositivo Bluetooth no robô para que uma porta COM virtual será criada.

Algumas placas de controlador de robô têm firmware que pode aceitar comandos usando uma linguagem simples comando. Por exemplo, com o serializador de RoboticsConnection (que obtém seu nome de seu uso de um protocolo serial), você pode digitar comandos para o controlador por meio de um programa de terminal, como o HyperTerminal. Comandos são todos legíveis e encerrar cada pressionando Digite.

Se você estiver criando seu próprio protocolo para uso com um robô, você precisará fazer algumas opções. Primeiro, você deve decidir se irá enviar dados binários. Converter valores binários em hexadecimal ou decimal para transmissão exige mais largura de banda e aumenta o processamento de sobrecarga de CPU na placa. Por outro lado, faz lê as mensagens muito mais fácil e você não tenha qualquer comportamento estranho devido a caracteres de controle misinterpreted.

A próxima pergunta é se você deseja usar pacotes de tamanho fixo ou um formato mais flexível de comprimento variável. Comprimento fixo é mais fácil de analisar e funciona melhor com hexadecimal.

Você também deve considerar se você usará uma soma de verificação. Para a comunicação de computador a computador calculando dígitos de verificação é fácil. Se, no entanto, você deseja testar seu robô, digitando comandos manualmente, descobrir os dígitos de verificação fica muito complicado. Ao usar as somas de verificação, 
typically o receptor envia fazer um reconhecimento (ACK) ou confirmação negativa (NAK) dependendo se o comando veio com êxito ou não. Sua decisão sobre o uso de uma soma de verificação realmente se reduz à confiabilidade da conexão.

O serviço de SerialPort

Ele deve ser aparente por agora porque um serviço de porta serial seria útil. O pacote do RDS, entretanto, não inclui um serviço, embora muitos dos exemplos robô usam links de comunicação serial. Se explorar o código de exemplo RDS, você encontrará o que cada exemplo manipula a porta serial diferente. Este artigo descreve uma abordagem para usando uma porta serial. Não é a única maneira de fazê-lo e não necessariamente a melhor maneira.

Antes de colocar qualquer ainda mais, certifique-se de que você tenha baixado e instalado RDS. O download para este artigo contém o código-fonte do serviço 
SerialPort. Descompacte-o em uma pasta sob o diretório de instalação do RDS (também conhecido como o ponto de montagem). Observe que você deve manter seu código separada na pasta Exemplos que acompanha o RDS para que você Don misturar seu código com o código do Microsoft. Além disso, é recomendável colocar seu código sob o ponto de montagem do RDS em vez de em outro lugar no seu disco rígido, porque ele simplifica o desenvolvimento. Tenho uma pasta de projetos onde evitar todo o meu próprio código nas subpastas, facilitando o backup.

Os arquivos principais no código-fonte SerialPort são SerialPort.cs, SerialPortTypes.cs e SerialPort.manifest.xml.

SerialPort.cs contém a implementação de serviço ou o comportamento. Ele consiste na classe de serviço, que contém os manipuladores de operação, além disso, qualquer necessário oferecer suporte a métodos e variáveis.

SerialPortTypes.cs contém as definições do estado do serviço, os tipos de operação e tipos de mensagem. Na verdade, ela descreve a interface para o serviço e não deve conter qualquer código executável. Este é um ponto-chave sobre um contrato de serviço — é apenas uma definição de dados.

SerialPort.manifest.xml é chamado de manifesto e descreve como serviços são combinados ou coordenados para executar um aplicativo. Esse arquivo é usado como entrada para o utilitário DssHost, que cria um nó DSS serviços executados dentro. Nesse caso o manifesto é executado somente o serviço de SerialPort, que é bem inútil. Um manifesto útil também especifique outros serviços que dependem do serviço de SerialPort para estabelecer conexões.

Antes de usar o serviço de SerialPort, você deve executar a ferramenta DssProjectMigration e em seguida, recompile o serviço. Abra um prompt de comando do DSS (veja em RDS no menu Iniciar) e verifique se que os caminhos configurados para que você pode executar arquivos na pasta \bin. Em seguida, altere o diretório onde você descompactou o código e digite o comando a seguir:

Dssprojectmigration /b- .

O /b-option significa Don criar uma cópia de backup e o caractere ponto (.) se refere ao diretório atual.

Você pode compilar o serviço no Visual Studio ou fazê-lo a partir da linha de comando digitando:

Msbuild serialport.sln

Compilar o serviço gera o DLL de serviço, um DLL do proxy e uma transformação DLL (que converte os tipos de dados entre o DLL de serviço e o proxy). Esses serão todos colocados na pasta \bin sob o ponto de montagem do RDS. Você também deve manter os arquivos de manifesto e config juntos copiando-os para a pasta \Exemplos\config (embora isso não é essencial).

O contrato de serviço

Cada serviço possui um identificador exclusivo do contrato, que é declarado no arquivo Types.cs e se parece com uma URL. Observe, entretanto, que ela tem nenhum significado na Web e usando um identificador de estilo de URL é apenas uma maneira conveniente de garantir a exclusividade, permitindo que as organizações criem seus próprios espaços para nome. (Para projetos você precisará usar um espaço para nome diferente de microsoft.com/robotics.) SerialPortTypes.cs contém a seguinte definição:

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

Um contrato de serviço também inclui o estado e operações que definem quais propriedades podem manipular outros serviços e como. SerialPortState (consulte Figura 1) inclui a configuração da porta serial, alguns parâmetros para tempos limite e o último byte recebidos durante a operação assíncrona.

Figura 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; }
  }
}

Você pode definir seus próprios tipos de dados para uso nos tipos de estado e a mensagem. Neste serviço, há uma classe SerialPortConfig. Para tornar visíveis no proxy, ele deve ser público e marcado com o atributo [DataContract]. Cada propriedade da classe deve ser declarado como pública e também ser marcadas usando o atributo [DataMember]. Se isso não for feito, a propriedade não poderá ser acessada.

Também é possível expor enums pública — dessa forma Don é necessário usar mágica números no código que usa o serviço de outros programadores. É recomendável programação prática, também, porque ela permite a verificação de tipo de dados.

Quando você cria um serviço, você precisa decidir como outros serviços irão interagir com ele. Este serviço SerialPort suporta as seguintes operações listadas abaixo em grupos lógicos:

  • Obter, inscrever
  • ReceiveByte
  • SetConfig, abrir, fechar, ClearBuffers
  • ReadString ReadByte, ReadByteArray,
  • WriteString WriteByte, WriteByteArray,

Observe que a operação ReceiveByte é para uso interno pelo serviço propriamente dito e não deve ser usada por outros serviços. Falarei mais sobre o assunto mais tarde.

As operações de leitura e gravação são todos síncronas — o serviço não responde até que a operação seja concluída. Se você abrir a porta serial no modo assíncrono (explicado abaixo), o serviço de enviar uma notificação ReceiveByte para cada byte recebido e você não deve usar as operações de leitura. No entanto, as operações de gravação, sempre são síncronas.

Cada operação tem um tipo de mensagem solicitação e um tipo de mensagem de resposta. Alguns deles podem ter propriedades e outras estarão vazias — o tipo de dados é suficiente para transmitir a mensagem apropriada.

Comportamento de serviço

Como observado anteriormente, o código executável do serviço está em SerialPort.cs. Todos os serviços são derivados do DsspServiceBase, que fornece uma série de propriedades e métodos auxiliares. Quando um serviço é iniciado, o método Start é chamado:

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

Início cuida de inicializar o estado (se necessário) e abrindo a porta serial automaticamente se OpenOnStart foi especificada no arquivo de configuração (explicado abaixo).

Cada operação é suportada por um serviço deve ter um manipulador de serviço. Mas, algumas operações, como, por exemplo, soltar e Get, são manipuladas pela infra-estrutura (a menos que você deseja substituir o comportamento padrão).

O OpenHandler mostra um manipulador muito simples:

[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”));
  }
}

Esse manipulador chama OpenPort, um método interno. Se for bem-sucedida, uma resposta será lançada novamente. Como nenhuma informação tiver a ser retornado, isso é apenas uma resposta padrão fornecida pelo DSS.

Se a abertura falhar, uma exceção é lançada. DSS captura a exceção e o converte em uma falha, o que é enviada de volta como resposta. Embora não imediatamente óbvio, se ocorrer uma exceção no OpenPort, ele também emergir e retornar uma falha.

Não é necessário explicar todo o método OpenPort, mas um ponto é importante — você pode abrir a porta serial para operação síncrona ou assíncrona. No modo síncrono, todas as solicitações de leitura e gravação completas antes de retornar uma resposta. No entanto, se você abrir no modo assíncrono, as notificações são enviadas para cada caractere recebido. Para que isso funcione, o código define um manipulador de eventos convencional:

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

O manipulador de eventos é mostrado na Figura 2. Esse manipulador é executado em um segmento .NET. Mas para interoperar com DSS, ele deve ser alternado para um segmento CCR, para que o código lança uma solicitação ReceiveByte à porta do serviço operações principais. Depois de lançar uma solicitação, o código deve receber a resposta, caso contrário, haverá um vazamento de memória. Essa é a finalidade de Arbiter.Choice, que usa a notação abreviada translation from VPE for Csharp para delegados anônimos para lidar com as duas respostas possíveis. Um Activate é necessário para colocar o receptor Choice em fila ativa. Apenas uma falha é relevante nesse caso, e um resultado bem-sucedido não faz nada.

Figura 2 Manipulador de eventos

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"); }
      ));
  }
}

O manipulador ReceiveByte será executado em seguida para processar o novo caractere:

[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);
}

O atributo [DmServer] permite DSS conectar o manipulador para a porta operações durante a inicialização do serviço. O manipulador envia uma notificação para os assinantes e, em seguida, é postada uma resposta que dizia que a operação é concluída. (Serviços que desejem receber notificações devem enviar uma operação de inscrever-se para o serviço de SerialPort).

Leia manipuladores de serviço para o outro e as operações de gravação são bastante auto-explicativos. O WriteStringHandler (consulte Figura 3) contém uma pequena ruga, porém — pode inserir um pequeno atraso entre o envio de caracteres. Isso foi projetado para ajudar Microcontroladores mais lento que podem Don ser capaz de acompanhar as mudanças se os dados são enviados a plena velocidade 
especially dispositivos como o BasicStamp bit estrondos e que Don têm um hardware Universal Asynchronous Receiver/Transmitter (UART), para que eles executam I/O serial no software.

Figura 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;
}

Outro ponto sobre esse manipulador é que é um iterador. Observe a declaração do método que IEnumerator <itask>e o fato de que ele usa yield retornar e yield break. Este recurso da linguagem translation from VPE for Csharp permite que a CCR para suspender tarefas sem bloquear um segmento. Quando o yield return é executado, o thread executar o método é retornado ao pool. Depois que o tempo limite for concluído, ele volta posta uma mensagem que faz com que a execução continuar, embora possivelmente em um thread diferente.

Configurando o serviço

Um arquivo de configuração é uma versão XML serializado do estado do serviço que é carregado durante a inicialização do serviço. É uma boa idéia para oferecer suporte a um arquivo de configuração pois permite que você alterar o comportamento do serviço sem recompilar. Isso é especialmente importante para definir o número da porta COM.

Você pode especificar o nome do arquivo no serviço quando você declara a instância de estado (em SerialPort.cs):

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

Nesse caso, nós já declarado config como opcional; caso contrário, o serviço não iniciado se o arquivo config está ausente. Por outro lado, isso significa que você precisa verificar o estado do método de iniciar o serviço e inicializá-lo para alguns padrões sensato, se necessário.

Porque nenhum caminho foi especificado para o ServiceUri, DSS assumirá que o arquivo é na mesma pasta como o manifesto usada para iniciar o serviço. Figura 4 mostra o conteúdo de um arquivo de configuração típica.

Figura 4 Arquivo de configuração para 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>

Observe que esse arquivo de configuração não solicita o serviço para abrir a porta COM automaticamente, para que você vai precise enviar uma solicitação Open.

Se desejar que seu serviço para ter uma aparência profissional, você precisará prestar atenção a detalhes como a descrição de serviço e ícones. Mesmo se você Don planeja usar VPL sozinho, ele é uma boa idéia testar seu serviço em VPL e torná-lo VPL amigável para que outras pessoas possam usá-lo facilmente.

Você pode decorar sua classe de serviço com dois atributos que descrevem o serviço:

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

Exibe o primeiro atributo como o nome do serviço na lista serviço VPL (consulte Figura 5), e o segundo atributo aparece como uma dica de ferramenta se você passar o mouse sobre o nome do serviço na lista.


Figura 5 Lista de serviços VPL

Se você tiver um site da Web e você deseja documentar seus serviços on-line, você pode anexar outro atributo à classe de serviço para fornecer o hiperlink:

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

Quando esse atributo VPL, ele adiciona um ícone de informação pequeno (um branco “ i ” em um disco azul) ao lado do serviço na lista de serviço.

Se você adicionar ícones a seu serviço, que você poderá facilmente fazer será aparecem em diagramas VPL e a lista de serviço. Observe o ícone pequeno, denominado uma miniatura ao lado do nome do serviço em Figura 5. Figura 6 ilustra a versão maior do ícone, o que será exibido dentro do bloco que aparece em diagramas VPL.


Figura 6 Bloco de serviço

Ao adicionar essas imagens a um projeto, verifique se que você alterar as propriedades de arquivo para que seja definida Build Action para Embedded Resource. PNG é o formato de arquivo preferido porque ele oferece suporte a um canal alfa. Isso permite que você criar um ícone com um plano de fundo transparente, definindo o valor alfa na cor de plano de fundo como zero.

A imagem do ícone de serviço deve ser 32 x 32 pixels e 16 por 16 a miniatura. Os nomes de arquivo das imagens devem começar com o nome de classe de serviço, em SerialPortService esse caso. Assim que eu fiz os nomes de arquivo para o meu exemplo SerialPortService.Image.png e SerialPortService.Thumbnail.png.

Usando o serviço

O serviço é bastante flexível. Você pode especificar a configuração da porta serial em um arquivo de configuração (que é a maneira mais comum) ou enviando uma solicitação SetConfig. Uma vez que você tenha definido a configuração, você pode chamar a operação de abrir. Para sua conveniência, um sinalizador no arquivo de configuração fará com que o serviço abrir a porta automaticamente na inicialização. Se a porta já estiver aberta, a chamada Open irá primeiro fechar e, em seguida, reabri-la.

Você precisa decidir como deseja usar o serviço: forma síncrona ou assíncrona. Ao operar no modo síncrono, cada ler ou solicitação de gravação aguardará até que a operação seja concluída antes de enviar uma resposta de volta. Em termos de VPL, essa é uma abordagem simples, porque o fluxo de mensagens fará uma pausa no bloco SerialPort no diagrama. Observe que a operação assíncrona não é totalmente assíncrona — gravar operações ainda ocorrem sincronicamente. Mas cada novo byte recebido é enviada como uma notificação para os assinantes.

Em teoria, cada operação de modificação de estado em um serviço deve causar uma notificação seja enviada para que os assinantes podem manter sua própria versão armazenada em cache do estado do serviço. Isso significa que todas as operações com base em operações DSSP substituir, atualizar, inserir, excluir e Upsert devem enviar uma notificação correspondente. No entanto, os desenvolvedores muitas vezes reproduzir rapidamente e soltos com esse requisito.

Para simplificar, o serviço de SerialPort apenas envia notificações usando o tipo de operação ReceiveByte quando no modo assíncrono. Abrir, fechar, e operações SetConfig também fazer com que as notificações de envio.

Porque as operações de leitura e gravação não modifiquem o estado, eles são uma subclasse desativar a operação de envio DSSP. É claro tem um efeito colateral, que é receber e enviar dados sobre o link serial.

Testando com VPL

O download deste artigo inclui dois programas VPL de amostra, EchoAsynch e EchoSynch, que mostram como usar o serviço do modo assíncrono (por meio de notificações) e modo síncrono. As Exemplos VPL usar arquivos de configuração para definir os parâmetros iniciais para a porta COM, incluindo o número da porta (que é definido como 21 nos arquivos config e deve ser alterado para corresponder ao endereço de porta COM do seu computador).

Observe que para testar o serviço será necessário um cabo de modem nulo e dois computadores com portas seriais ou duas portas no mesmo computador. Dispositivos USB para serial estão prontamente disponíveis, portanto, é bastante possível ter várias portas seriais em um único PC. Quando você tem as portas COM conectados juntos, execute um emulador de terminal como o HyperTerminal e conecte a uma das portas COM. Inicie executando o programa EchoAsynch VPL a porta serial. (É possível encontrar VPL no menu Iniciar, em RDS). Quando você digita na janela de emulador de terminal, você deve ver os caracteres ecoados.

Você pode usar VPL para criar arquivos de configuração. Clique em um bloco de serviço SerialPort no diagrama e procure no painel Properties. Você deve visualizar algo como Figura 7. Certifique-se de que o PortNumber está definida corretamente para o seu PC. (Deve ser a porta serial, não do que você abrir no emulador de terminal). Você perceberá que a paridade e StopBits são listas suspensas. As entradas usando estas listas de vir diretamente de enums SerialPortTypes.cs definidos.


Figura 7 Configuração do serviço de porta serial

Este é um local onde os comentários doc XML muito útil. Quando você coloca o cursor sobre um parâmetro de configuração com o cursor do mouse, uma dica de ferramenta será exibida mostrando o comentário correspondente para cada membro de estado.

Quando você executa o programa EchoAsynch VPL, a primeira parte do programa no Figura 8 abre a porta serial no modo assíncrono.


Figura 8 Abrindo a porta serial no modo assíncrono

Se você tiver inserido valores inválidos no config, como uma taxa de transmissão incorreta, abrir falhará. (Ele pode também falhar se a porta COM está em uso, a porta Don ou você Don tem as permissões apropriadas). É por isso que o programa verifica se há uma falha e exibe-o.

O resto do programa (consulte Figura 9) apenas exibe cada caractere recebido. Ele faz isso utilizando os caracteres de ReceiveByte notificações e enviá-las novamente usando WriteByte.

Para facilitar a leitura de saída, um carro retornar caractere (ASCII 13, decimal) tem um avanço de linha (10) anexado para que irá mover o cursor para a próxima linha na janela do seu emulador de terminal. Observe que todos o SerialPortService bloqueia no Figura 9 diagrama se referir à instância do serviço mesma.


Figura 9 Programa EchoAsynch

O programa EchoSynch VPL (consulte Figura 10) usa o modo de operação síncrono — ele não usa notificações. (Na verdade, as notificações são enviadas nunca no modo síncrono).


Figura 10 O programa EchoSynch

Ao contrário de programa anterior, este usa ReadString e WriteString aos dados de eco. Essas operações executam funções semelhantes aos de ReadByteArray e WriteByteArray, contudo, seqüências de caracteres são mais fáceis de lidar com VPL de matrizes de bytes.

As operações de seqüência de caracteres usar um caractere de avanço de linha (ou nova linha) como um marcador de fim de linha. Portanto, ReadString completa quando você pressiona avanço de linha (Ctrl-J) não quando você pressionar ENTER. Isso pode ser confuso na primeira vez que você teste o programa usando um emulador de terminal, porque você deve estar imaginando por que nada está repetindo. WriteString adiciona um retorno de carro e avanço de linha para a saída para que cada seqüência de caracteres é exibido em uma linha separada.

Observe que o arquivo de configuração EchoSynch tem um InterCharacterDelay de 500ms. Isso faz com que as seqüências de caracteres a ser enviado muito lentamente. Você pode tentar alterar esse valor.

Trevor Taylor Ph.D., é o gerente de programa Robotics Developer Studio na Microsoft. Ele é co-autor, com Kyle Johns, de “ Professional Robotics Developer Studio ” (Wrox, 2008). Código de exemplo do livro está disponível no promrds.com.

* *

Graças aos seguintes especialistas técnicos para revisar este artigo: Kyle Johns