Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 05-05-2008
vejerf vejerf is offline
Miembro
 
Registrado: ene 2007
Posts: 206
Poder: 18
vejerf Va por buen camino
Lectura de tramas: <SYN><DLE><STX> ... <DLE><ETX>

Hola,
Estoy realizando una aplicación que lee datos del puerto serie. Los datos que me llegan los almaceno en un buffer de recepción de bytes. Este buffer tiene la siguiente estructura:
Código Delphi [-]
 
TBUFFER_ENTRADA = record
    Numero_Datos     : integer;
    Puntero_Entrada  : integer;
    Puntero_Salida   : integer;
    Datos            : array [1..LONGITUD_BUFFERS] of Byte;
  end;

Las tramas que me llegan tienen el siguiente formato:
<SYN><DLE><STX> ... <DLE><ETX>

Mi problema es que soy capaz de leer tramas, pero con mi forma de hacerlo parece ser que alguna se me escapa. Tiene alguien algún método para leer tramas de ese tipo???

Muchas gracias...
Responder Con Cita
  #2  
Antiguo 05-05-2008
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Question

Cita:
Empezado por vejerf Ver Mensaje
...Mi problema es que soy capaz de leer tramas, pero con mi forma de hacerlo parece ser que alguna se me escapa...
Bueno, creo que sería necesario que nos dijeras cuál es esa forma de hacerlo y, ya encarrerado el ratón, el componente, biblioteca o grupo de funciones que estás utilizando.

Esperamos tu retroalimentación.

Saludos.

Al.
Responder Con Cita
  #3  
Antiguo 06-05-2008
vejerf vejerf is offline
Miembro
 
Registrado: ene 2007
Posts: 206
Poder: 18
vejerf Va por buen camino
A continuación pongo el código con el que leo las tramas. El buffer que utilizo es un buffer circular. Uso un componente llamado TVaComm para usar el puerto serie. Cuando recibo un carácter por el puerto serie se produce el evento en el que compruebo si tengo una trama completa. El código es el siguiente:

Código Delphi [-]
procedure TSimuladorThorcomForm.PuertoSerieRxChar(Sender: TObject;
  Count: Integer);
var
  Estado      : integer;
  CONTADOR    : integer;
  NumeroBytes : integer;
  FinalTrama : boolean;
  FlagLongitud : boolean;
  NBytes : Integer;
  I : Integer;
  NumeroDatos : integer;
  Datos : Byte;
  DatoHx : String;
  PunteroAux1 : Integer;
  PunteroAux2 : Integer;
begin
  NumeroBytes := (Sender as TVaComm).ReadBufUsed;
  CONTADOR := 1;
  Datos := 0;
  //Se leen los bytes que estén en la cola de recepción a la espera de ser leídos y se meten en el buffer circular
  for CONTADOR := 1 to NumeroBytes do
  begin
    Estado := (Sender as TVaComm).ReadBuf(BUFFER_RX.Datos[BUFFER_RX.Puntero_Entrada],1);
    Datos :=  BUFFER_RX.Datos[BUFFER_RX.Puntero_Entrada];
    if ( (Datos < 32) or (Datos > 122) ) then
      DatoHx := IntToHex(Byte(BUFFER_RX.Datos[BUFFER_RX.Puntero_Entrada]),2)
    else
      DatoHx := Char(BUFFER_RX.Datos[BUFFER_RX.Puntero_Entrada]);
    CuadroTX.Lines.Text := CuadroTX.Lines.Text +' '+ DatoHx;
    inc(BUFFER_RX.Puntero_Entrada);
    if BUFFER_RX.Puntero_Entrada > Longitud_Buffers then
      BUFFER_RX.Puntero_Entrada := 1;
    inc(BUFFER_RX.Numero_Datos);
    if BUFFER_RX.Numero_Datos > Longitud_Buffers then
      BUFFER_RX.Numero_Datos := 1;
  end;
  //Buscamos el comienzo de trama 
  while ( (BUFFER_RX.Datos[BUFFER_RX.Puntero_Salida] <> SYN) and (BUFFER_RX.Numero_Datos <> 0) ) do
  begin
    inc(BUFFER_RX.Puntero_Salida);
    if BUFFER_RX.Puntero_Salida > Longitud_Buffers then
      BUFFER_RX.Puntero_Salida := 1;
      dec(BUFFER_RX.Numero_Datos);
  end;
  if BUFFER_RX.Puntero_Salida = Longitud_Buffers then
  begin
    PunteroAux1 := 1;
    if PunteroAux1 = Longitud_Buffers then
      PunteroAux2 := 1
    else
      PunteroAux2 := PunteroAux1 + 1;
  end
  else
  begin
    PunteroAux1 := BUFFER_RX.Puntero_Salida + 1;
    if PunteroAux1 = Longitud_Buffers then
      PunteroAux2 := 1
    else
      PunteroAux2 := PunteroAux1 + 1;
  end;
  FinalTrama := false;
  while ( ( (BUFFER_RX.Datos[BUFFER_RX.Puntero_Salida] <> SYN) or (BUFFER_RX.Datos[PunteroAux1] <> DLE)
            or (BUFFER_RX.Datos[PunteroAux2] <> STX) ) and (BUFFER_RX.Numero_Datos >0) ) do
  begin
    inc(BUFFER_RX.Puntero_Salida);
    if BUFFER_RX.Puntero_Salida > Longitud_Buffers then
      BUFFER_RX.Puntero_Salida := 1;
    dec(BUFFER_RX.Numero_Datos);
    if BUFFER_RX.Puntero_Salida = Longitud_Buffers then
    begin
      PunteroAux1 := 1;
      if PunteroAux1 = Longitud_Buffers then
        PunteroAux2 := 1
      else
        PunteroAux2 := PunteroAux1 + 1;
    end
    else
    begin
      PunteroAux1 := BUFFER_RX.Puntero_Salida + 1;
      if PunteroAux1 = Longitud_Buffers then
        PunteroAux2 := 1
      else
        PunteroAux2 := PunteroAux1 + 1;
    end;
  end;
  //Buscamos el final de trama
  while ( ( (BUFFER_RX.Datos[PunteroAux2] <> ETX) or (BUFFER_RX.Datos[PunteroAux1] <> DLE) )
            and (PunteroAux1 <> BUFFER_RX.Puntero_Entrada) ) do
  begin
    inc(PunteroAux1);
    if PunteroAux1 > Longitud_Buffers then
      PUnteroAux1 := 1;
    inc(PunteroAux2);
    if PunteroAux2 > Longitud_Buffers then
      PunteroAux2 := 1;
    if ( (BUFFER_RX.Datos[PunteroAux1] = DLE) and (BUFFER_RX.Datos[PunteroAux2] = ETX) ) then
      FinalTrama := true;
  end;
  //Si hay una trama completa en el BUFFER_RX la extraemos para procesarla
  if FinalTrama = true then
  begin
    FinalTrama := false;
    NBytes := 0;
    for I := 1 to Longitud_Buffers do
      TRAMA[i] := 0;
    I := 1;
    while ( (BUFFER_RX.Puntero_Salida <> PunteroAux2) and (BUFFER_RX.Numero_Datos <> 0) ) do
    begin
      TRAMA[i] := BUFFER_RX.Datos[BUFFER_RX.Puntero_Salida];
      inc(NBytes);
      inc(I);
      inc(BUFFER_RX.Puntero_Salida);
      if BUFFER_RX.Puntero_Salida > Longitud_Buffers then
        BUFFER_RX.Puntero_Salida := 1;
      dec(BUFFER_RX.Numero_Datos);
    end;
    inc(NBytes);
    TRAMA[NBytes] := ETX;
    DesempaquetarTrama(NBytes);
  end;
end;

Lo que hago primero es tomar los bytes del puerto serie y meterlos en el buffer de recepción. A continuación compruebo si hay una trama completa y si la hay la desempaqueto.

Quizás no sea la forma más práctica ni ortodoxa, pero más o menos me funciona jeje

Muchas gracias...
Responder Con Cita
  #4  
Antiguo 06-05-2008
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por vejerf Ver Mensaje
Quizás no sea la forma más práctica ni ortodoxa, pero más o menos me funciona
Hola vejerf

Para este tipo de menesteres y desde mi experiencia con la recepción de paquetes de datos a través de puerto serial, te recomiendo que uses el componente TurboPower Async Professional (gracias amigo Al por recomendarmelo hace ya unos años ), el cual tiene dentro de sus particularidades un objeto de nombre ApdDataPacket, a este objeto le asignas una cadena de inicio y una cadena de final por ejemplo:

En las propiedades del Objeto ApdDataPacket

StartString = #22 [SYN] (Aunque yo usaria solo #2 [STX], a menos que requieras por fuerza el [SYN])
EndString = #3 [ETX];

y en código solo requieres hacer esto:

Código Delphi [-]
procedure TLector.ApdDataPacket1StringPacket(Sender: TObject; Data: string);
begin
  ProcesaInformacion(Data); //Data ya tiene todo el paquete de datos que esperas.
end;

Al final, te olvidas de codificar y validar cada vez que recibes un caracter.

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #5  
Antiguo 07-05-2008
vejerf vejerf is offline
Miembro
 
Registrado: ene 2007
Posts: 206
Poder: 18
vejerf Va por buen camino
Gracias por tu ayuda Egostar... pero... pero...
El componente que uso es el TVaComm. Este viene junto con otra serie de componentes en un paquete llamado Async32 si no me equivoco. Otro de los componentes que trae es el TVaCapture que funciona como tu dices. Le indicas el comienzo y el fin de trama y cuando detecta ese comienzo y fin produce un evento que tiene como parámetro el contenido del paquete. El problema que me encontré es que el modem que uso devuelve los caracteres hexadecimales y el componente TVaCapture devuelve caracteres ASCII. En principio para algunas cosas me es igual, pero me he dado cuenta de un pequeño fallo. Resulta que el modem devuelve en muchas tramas el valor $00 (carácter NULL) y TVaCapture lo devuelve en el String de datos como un espacio en blanco ($20 si no me equivoco). Entonces esto a veces me lleva a error xq puede que alguna vez sí sea verdaderamente un espacio o a veces sea un NULL. Y estos valores puede que me sean necesarios saber el valor exacto.
No sé si después de todo este palabrerío se me habrá entendido jeje.

De todas formas... muchísimas gracias por el consejo!!!
Responder Con Cita
  #6  
Antiguo 07-05-2008
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por vejerf Ver Mensaje
...El componente que uso es el TVaComm. Este viene junto con otra serie de componentes en un paquete llamado Async32 si no me equivoco. Otro de los componentes que trae es el TVaCapture que funciona como tu dices. Le indicas el comienzo y el fin de trama y cuando detecta ese comienzo y fin produce un evento que tiene como parámetro el contenido del paquete...
Sólo como dato, te comento que usas los mismos componentes que yo utilizaba antes de descubrir los de TurboPower que te sugiere Eliseo, los cuales encontré más potentes y funcionales. Y es bastante problable que con ellos tengas menos problemas.

Saludos.

Al.
Responder Con Cita
  #7  
Antiguo 07-05-2008
vejerf vejerf is offline
Miembro
 
Registrado: ene 2007
Posts: 206
Poder: 18
vejerf Va por buen camino
Cita:
Sólo como dato, te comento que usas los mismos componentes que yo utilizaba antes de descubrir los de TurboPower que te sugiere Eliseo, los cuales encontré más potentes y funcionales. Y es bastante problable que con ellos tengas menos problemas
Pues ante esto sólo me resta rendirme ante la evidencia. Soy un poco reacio a cambiar de componentes cuando ya más o menos sé el comportamiento de cada uno, pero supongo que por echar una ojeada a los que recomendáis no pierdo nada.

Muchas gracias otra vez a los dos!!!
Responder Con Cita
  #8  
Antiguo 08-05-2008
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por vejerf Ver Mensaje
Pues ante esto sólo me resta rendirme ante la evidencia. Soy un poco reacio a cambiar de componentes cuando ya más o menos sé el comportamiento de cada uno, pero supongo que por echar una ojeada a los que recomendáis no pierdo nada.

Muchas gracias otra vez a los dos!!!
Sin saber como funciona tu componente y viendo que no te gusta mucho la idea, te pongo un pequeño código con lo que yo haría, digamos que es el esquema general de la lectura de puertos que normalmente yo realizo, es obvio que puede tener fallos, pero lo que quiero mostrar es que no necesitas tanto código para lo que quieres.

Código Delphi [-]
procedure TSimuladorThorcomForm.PuertoSerieRxChar(Sender: TObject;
  Count: Integer);
var
  I : Integer;
  Dato : Byte;
  Linea,DatoHx : String;
begin
  for I := 1 to count do begin
      Dato := ord(TVaComm1.GetChar); //Suponiendo que exista esa funcion (GetChar)
      DatoHx := IntToHex(Dato);
      case Dato of
           22: begin //Si es SYN, limpio la cadena para ingresar datos nuevos.
                    Linea := '';                             
           end;
           3: begin //Si es ETX, procedo a realizar lo que se tenga que hacer con el paquete de datos
                  Hago_lo_que_Sea(Linea);
           end;
      end;
      Linea := Linea +' '+ DatoHx; //Agrego todos los caracteres que le lleguen al puerto.
  end; 
end;

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #9  
Antiguo 08-05-2008
vejerf vejerf is offline
Miembro
 
Registrado: ene 2007
Posts: 206
Poder: 18
vejerf Va por buen camino
Gracias por tomarte la molestia de realizar un código para la lectura del puerto serie. Una pequeña pega que le veo es que la variable linea debería ser global y no local, ya que puede que no lleguen todos los caracteres de la trama en el momento en que se produzca el evento. Quizás llegue en dos veces por lo que la variable se habrá vuelto a inicializar y supongo que no funcionará, no?

Salu2...
Responder Con Cita
  #10  
Antiguo 08-05-2008
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por vejerf Ver Mensaje
Gracias por tomarte la molestia de realizar un código para la lectura del puerto serie. Una pequeña pega que le veo es que la variable linea debería ser global y no local, ya que puede que no lleguen todos los caracteres de la trama en el momento en que se produzca el evento. Quizás llegue en dos veces por lo que la variable se habrá vuelto a inicializar y supongo que no funcionará, no?

Salu2...
Hola

Si y no, ya que al ser una comunicación serial, los caracteres te llegan como su nombre lo indica, de forma serial, uno tras otro, por lo que el conflicto que mencionas no creo que se presente ya que cuando te llega el primer caracter de la siguiente trama, inicializas la variable Linea.

La puse como local para que se viera, pero puedes hacerla global.

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #11  
Antiguo 08-05-2008
vejerf vejerf is offline
Miembro
 
Registrado: ene 2007
Posts: 206
Poder: 18
vejerf Va por buen camino
Hola de nuevo,

Cita:
Si y no, ya que al ser una comunicación serial, los caracteres te llegan como su nombre lo indica, de forma serial, uno tras otro, por lo que el conflicto que mencionas no creo que se presente ya que cuando te llega el primer caracter de la siguiente trama, inicializas la variable Linea.
Esto lo entiendo, pero yo lo que digo es que no tienen por qué llegarte todos los caracteres de una trama de una vez. Es decir si yo envío por ejemplo la siguiente trama por un puerto serie:
<STX>Esto es un ejemplo de una cadena por el puerto serie<ETX>

puede que la primera vez que se genera el evento llegue tan sólo:
<STX>Esto es un ejemplo de una cadena

esto tu lo almacenas en lína y a continuación te llega el resto de trama:
por el puerto serie<ETX>

Esto te llega la segunda vez que se genera el evento por lo que la variable línea se habrá vuelto a inicializar y no tendrá la trama completa por lo que se perdería.

Si no me equivoco este es el comportamiento del puerto serie, aunque para decir la verdad es ahora cuando lo estoy manejando por primera vez. Para evitar que se pierdan tramas lo que usaba yo es un buffer circular.

Un saludo egostar & cia...
Responder Con Cita
  #12  
Antiguo 08-05-2008
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por vejerf Ver Mensaje
Hola de nuevo,



Esto lo entiendo, pero yo lo que digo es que no tienen por qué llegarte todos los caracteres de una trama de una vez. Es decir si yo envío por ejemplo la siguiente trama por un puerto serie:
<STX>Esto es un ejemplo de una cadena por el puerto serie<ETX>

puede que la primera vez que se genera el evento llegue tan sólo:
<STX>Esto es un ejemplo de una cadena

esto tu lo almacenas en lína y a continuación te llega el resto de trama:
por el puerto serie<ETX>

Esto te llega la segunda vez que se genera el evento por lo que la variable línea se habrá vuelto a inicializar y no tendrá la trama completa por lo que se perdería.

Si no me equivoco este es el comportamiento del puerto serie, aunque para decir la verdad es ahora cuando lo estoy manejando por primera vez. Para evitar que se pierdan tramas lo que usaba yo es un buffer circular.

Un saludo egostar & cia...
Es que hay un detalle

Tu vas a recibir solo un SYN o si quieres un STX identificando que es una cadena nueva (yo prefiero usar STX, porque en un protocolo de este tipo la cadena valida esta siempre entre STX y ETX), es por eso que solo la incializamos cuando recibimos ese caracter, cuando sea cualquier otro estamos agregando los caracteres a Linea, y solo hasta que nos llegue ETX hacemos el proceso correspondiente de una cadena completa.

Edito: No importa cuantas veces nos mande caracteres para completar una sola trama completa

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney

Última edición por egostar fecha: 08-05-2008 a las 20:36:29.
Responder Con Cita
  #13  
Antiguo 08-05-2008
vejerf vejerf is offline
Miembro
 
Registrado: ene 2007
Posts: 206
Poder: 18
vejerf Va por buen camino
Cita:
Edito: No importa cuantas veces nos mande caracteres para completar una sola trama completa
Aja, es que yo pensaba que una vez que te sales del evento las variables locales una vez que vuelves a entrar se inicializaban. Por lo que tu dices no es así... corrígeme si me equivoco.
Responder Con Cita
  #14  
Antiguo 08-05-2008
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por vejerf Ver Mensaje
Aja, es que yo pensaba que una vez que te sales del evento las variables locales una vez que vuelves a entrar se inicializaban. Por lo que tu dices no es así... corrígeme si me equivoco.
Tienes razón, debe ser global.

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #15  
Antiguo 12-05-2008
vejerf vejerf is offline
Miembro
 
Registrado: ene 2007
Posts: 206
Poder: 18
vejerf Va por buen camino
Hola compañeros,

Tengo otro problema con el puerto serie y es debido a un overflow de los buffers que usa el componente TVaComm. Si empiezo a enviar cosas por el puerto serie puede que llegue un momento en el que desborde el buffer de transmisión (en recepción puede pasar lo mismo lógicamente, aunque ahora me preocupa más el de transmisión). Si os ha pasado esto alguna vez, ¿podríais darme alguna pista de como lo habeis solucionado?.

Muchas gracias...
Responder Con Cita
  #16  
Antiguo 28-06-2008
Avatar de richy08
richy08 richy08 is offline
Miembro
 
Registrado: may 2007
Ubicación: Bucerias, Nayarit Mexico
Posts: 529
Poder: 17
richy08 Va por buen camino
Cita:
Empezado por egostar Ver Mensaje
Hola vejerf

Para este tipo de menesteres y desde mi experiencia con la recepción de paquetes de datos a través de puerto serial, te recomiendo que uses el componente TurboPower Async Professional (gracias amigo Al por recomendarmelo hace ya unos años ), el cual tiene dentro de sus particularidades un objeto de nombre ApdDataPacket, a este objeto le asignas una cadena de inicio y una cadena de final por ejemplo:

En las propiedades del Objeto ApdDataPacket

StartString = #22 [SYN] (Aunque yo usaria solo #2 [STX], a menos que requieras por fuerza el [SYN])
EndString = #3 [ETX];

y en código solo requieres hacer esto:


Código Delphi [-]
procedure TLector.ApdDataPacket1StringPacket(Sender: TObject; Data: string);
begin
ProcesaInformacion(Data); //Data ya tiene todo el paquete de datos que esperas.
end;





Al final, te olvidas de codificar y validar cada vez que recibes un caracter.

Salud OS
buenos dtardes egostar estoy leyendo el post y me baje el componenet que mencionas lo pienso usar para leer el puerto serial de un conmutador, me podrias proporcionar algun manual de como usarlo mil gracias.
Responder Con Cita
  #17  
Antiguo 29-06-2008
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por richy08 Ver Mensaje
buenos dtardes egostar estoy leyendo el post y me baje el componenet que mencionas lo pienso usar para leer el puerto serial de un conmutador, me podrias proporcionar algun manual de como usarlo mil gracias.
Hola richy08

Puedes bajar los archivos de ayuda que tienen disponibles. tpapro_docs

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #18  
Antiguo 30-06-2008
Avatar de richy08
richy08 richy08 is offline
Miembro
 
Registrado: may 2007
Ubicación: Bucerias, Nayarit Mexico
Posts: 529
Poder: 17
richy08 Va por buen camino
ok gracias les echare un vistazo
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Lectura del USB por Interrupción cisco Varios 0 25-10-2007 18:13:29
Documentacion para Generar Tramas TCP bastardo10 Varios 0 07-06-2007 17:31:38
Lectura de un FTP con idHTTP gluglu Internet 2 05-05-2007 00:35:50
Problema de lectura de un cd dragondetierra Varios 0 18-02-2007 18:58:52


La franja horaria es GMT +2. Ahora son las 17:03:25.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi