IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants VCL Delphi Discussion :

[D7]CPort mange 2 octets ! pourquoi ?


Sujet :

Composants VCL Delphi

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    62
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 62
    Par défaut [D7]CPort mange 2 octets ! pourquoi ?
    Bonjour,

    Pour une application communicante par port série, j'utilise le composant CPort et pour des besoins de test local, le projet "com0com" pour simuler des ports virtuels.
    J'ai installé 2 séries de port: j'ai donc en port com virtuel CNCA0-CNCB0 et CNCA1-CNCB1.
    Mon appli de test (qui envoie les commandes) à CNCA0 pour port sortant et CNCB1 pour port entrant.
    Le programme qui reçoit les commandes et renvoie les réponses appropriées à CNCB0 pour port entrant et CNCA1 pour port sortant.

    La communication fonctionne, cependant il se passe quelque chose que je ne comprends pas, à l'arrivée de la commande j'ai perdu les deux premiers octets !!?

    Commande d'envoi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    procedure TForm1.btComPortCNCA0SendClick(Sender: TObject);
    var
      aPacket: TPacket;
    begin
      _GET_InPacket(@aPacket);
     
      //Résolution intermédiaire-Décalé le packet de 2 octets
      MovePacketToRight(@aPacket);
      MovePacketToRight(@aPacket);
     
      //Bouffe 2 octest
      ComPortCNCA0.Write(aPacket.Buffer, aPacket.Size);
    end;
    Mon type TPacket est défini ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const
      MAX_PACKET_SIZE = $0FFF;
    type
    TDataBuffer = array[0..MAX_PACKET_SIZE] of Byte;
    TPacket = record
        Size  : Word;
        Buffer: TDataBuffer;
      end;
      PPacket = ^TPacket;
    A la réception:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    procedure TMCSimulator.ComPortCNCB0RxChar(Sender: TObject; Count: Integer);
    var
      aPacket: TPacket;
    begin
      //Clean = Fill with 0
      CleanPacket(@aPacket);
     
      ComPortCNCB0.Read(aPacket, Count);
    //  aPacket.Size:= Count;
      aPacket.Size:= Count - 2; //Résolution intermédiaire - et lire 2 octets de moins
     
      //See received cmd
      ePacketReceived.Text:= DisplayBufferChr(aPacket);
    end;
    et donc si par exemple j'envoie:
    $7E $00 $01 $29 $09 $09 $11 $09 $22 $27 $00 $1E $12 $7E
    et bien je reçois
    $01 $29 $09 $09 $11 $09 $22 $27 $00 $1E $12 $7E $00 $00
    je perds donc les 2 premiers octets

    ma solution intermédiaire consiste à envoyer un paquet décalé de 2 octets vers la droite (ma fonction MovePacketToRight décale le packet de 1 et incrémente Packet.Size), ce qui m'oblige aussi à l'arrivée à lire 2 octets de moins, ce qui ne me plaît pas beaucoup au final et j'aimerais comprendre où sont passés mes deux premiers octets.

    D'où cela peut-il venir ?

  2. #2
    Membre Expert
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Par défaut
    avec ton type TPacket :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    [SIZE $7E00] [BUFFER $01 $29 $09 $09 $11 $09 $22 $27 $00 $1E $12 $7E $00 $00]
    ce qui est faux puisque la taille du buffer n'est pas $007E (126)


    SIZE = WORD donc taille maxi = 65536

    soit un buffer de 64Ko maxi.

    mais tu determine :

    const
    MAX_PACKET_SIZE = $0FFF;

    et $0FFF = 4095

    ce qui est faux egalement puisque si l'on veux un buffer de 4Ko il faut determiner comme suit :

    MAX_PACKET_SIZE = $1000; // 4096

    ou encore

    MAX_PACKET_SIZE = 4 shl 10; // 4096


    puis on declare completement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    {$ALIGN ON}
     
    const
      MAX_BUFFER_SIZE = 4 shl 10;
     
    type
      pDataBuffer = ^TDataBuffer;
      TDataBuffer = array[0..MAX_BUFFER_SIZE-1] of Byte;
     
      pPacket = ^TPacket;
      TPacket = record
         Size   : Word;
         Buffer : TDataBuffer;
      end;
    {
      TPacket structure : [Size 2][Buffer MAX_BUFFER_SIZE]
    }
     
    const
      SizeOfPacket = SizeOf(TPacket);

    il nous faut egalement une fonction utile qui permet de mettre à 0 les packets :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    procedure RAZPacket(const aPacket : pPacket);
    begin
      ZeroMemory(pointer(aPacket), SizeOfPacket);
    end;


    au moment de l'envois :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    var
      Pack : TPacket;
    begin
      // on initialise le packet :
      RAZPacket(@Pack);
     
     
      // on remplis le buffer
      {SetPacketBuffer}(@Pack.Buffer);
     
      // on determine la taille du packet
      {SetPacketSize}(@Pack.Size); 
     
      // le mieux etant d'avoir quelque chose du genre :
      Read(Pack.Buffer, Pack.Size);
     
      // puis on transmet 
      Send(Pack, Pack.Size+2); // +2 pour Size!
    end;

    quand on recupere

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    var
      Pack : TPacket;
    begin
      // On recois le packet
      Receive(Pack, SizeOfPacket); // si la taille est à determiner
     
      // ou encore :
      Pack.Size := Receive(Pack.Buffer);
    end;
    aprés tout depend de l'ensemble du programme.


    mais si on imagine un fonctionnement identique au Stream nous aurions cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    // send
    var
      Pack : TPacket;
    begin
      RAZPacket(@Pack);
      Pack.Size := StreamIn.Read(Pack.Buffer[0], MAX_BUFFER_SIZE);
     
      Socket.Send(Pack, Pack.Size+2);
    end;
     
    // receive
    var
      Pack : TPacket;
    begin
      RAZPacket(@Pack);
     
      Socket.Receive(Pack, SizeOfTPacket); // 2 + 4096
     
      if (Pack.Size > 0) and (Pack.Size < MAX_BUFFER_SIZE) then
        StreamOut.write(Pack.Buffer[0], Pack.Size)
      else
        raise Exception.CreateFmt('Erreur taille packet hors limite 0..%d (%d)',[MAX_BUFFER_SIZE, Pack.Size]);
    end;
    [ Sources et programmes de Dr.Who | FAQ Delphi | FAQ Pascal | Règlement | Contactez l'équipe ]
    Ma messagerie n'est pas la succursale du forum... merci!

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    62
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 62
    Par défaut
    Merci de ta réponse, un peu compliqué mais clair pour les types de données et les étendues.
    Ce n'est pas la réponse que j'attendais exactement bien qu'en la lisant j'y ai découvert mon erreur, dû à ma structure et à une inattention.

    Ma structure comme tu le marques est
    TPacket structure : [Size 2][Buffer MAX_BUFFER_SIZE]
    Or j'envoie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ComPortCNCA0.Write(aPacket.Buffer, aPacket.Size);
    Mais je lis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure ComPortCNCB0RxChar(Sender: TObject; Count: Integer);
    ..
       ComPortCNCB0.Read(aPacket, Count);
    ..
    le count est correct mais les deux premiers octets sont en fait copiés dans le Packet.Size (Word = 2 Octet), puis le reste dans le Packet.Buffer

    en rectifiant par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ComPortCNCB0.Read(aPacket.Buffer, Count);
    je récupère bien mes données correctement.

  4. #4
    Membre Expert
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Par défaut
    voila, oui mon explication etait un peu complexe j'avous.

    mais c'etait bien le probleme auquel je pensais. d'un coté tu envois le buffer et de l'autre plutot que recuperer Buffer tu recupere Packet ... donc forcement erreur de 2 octet...

    tu peux egalement transmettre un TPacket et recevoir un TPacket ce qui serait plus logique et plus fiable pour verifier que la transmittion c'est bien passée sur :

    ReadSize = Packet.Size+2
    [ Sources et programmes de Dr.Who | FAQ Delphi | FAQ Pascal | Règlement | Contactez l'équipe ]
    Ma messagerie n'est pas la succursale du forum... merci!

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    62
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 62
    Par défaut
    Merci encore de ton aide, ça m'a aidé plus que je ne pensais.

    tu peux egalement transmettre un TPacket et recevoir un TPacket ce qui serait plus logique et plus fiable pour verifier que la transmittion c'est bien passée sur :

    ReadSize = Packet.Size+2
    plus fiable
    Je préfère ne transmettre que le Buffer du packet, pour vérifier la transmission j'ai un CRC sur les deux derniers octet du buffer, c'est une meilleure vérification que juste la taille

    plus logique
    Pourquoi plus logique ?

  6. #6
    Membre Expert
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Par défaut
    si tu as un CRC oui, tester la taille n'est pas important.

    par contre, en cas de rupture du flux tu doit quand même savoir si la taille du buffer et au moins egale a la taille du CRC et inferieure a la taille maxi du buffer :


    CRC 16
    ReceiveOk = (RS >= 2) and (RS < MAX_BUFFER_SIZE);

    CRC 32
    ReceiveOk = (RS >= 4) and (RS < MAX_BUFFER_SIZE);


    la aussi on pourrais modifier encore TPacket en :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    TPacket = record 
      Size : word;
      Buffer: array[0..MAX_BUFFER_SIZE-1] of byte;
      CRC : word ou longword; (CRC16 ou CRC32)
    end;
    et donc transmettre un TPacket et gagner 2 ou 4 octet dans le buffer.
    pas trés important en fait.

    puis faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    RS = ReceiveBuffer(Packet);
    if (Packet.Size+2+[2|4]) = RS then
    begin
      if CRC(Packet.Buffer, Packet.Size) = Packet.CRC then
        // ok
      else
        // erreur CRC : buffer corrompus
    end
    else
      // erreur transmittion : perte de données

    sinon autre alternative :
    on integre la taille et le crc au buffer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    TPacket = record case integer of
      0: (Size, CRC: word; Datas: array[0..MAX_BUFFER_SIZE-1-2-2] of byte);
      1: (Buffer: array[0..MAX_BUFFER_SIZE-1] of byte);
    end;
    ici taille Packet = Taille de buffer (4096 dans ta configuration).
    dont 2 octet reservé pour la taille et 2 pour le CRC.

    ici Size, Crc et Datas permettent de lire facilement les données à l'interieur de Buffer, plutot que de jouer avec des pointeurs ou autres methodes de reconstruction du CRC ou Size a partir de SHL, SHR et a grand coups de Move ou copymemory.

    soit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    01 23 4567...n // index
    SS CC DDDD...D // Size, Crc, Datas
    BB BB BBBB...B // Buffer
    et grace a cette astuce on peu indiferement envoyer un TPacket ou TPacket.Buffer et recevoir dans un TPacket.Buffer ou TPacket ...

    bien dans l'exemple la taille alloué pour les données réelles n'est plus de 4096 octets mais de 4092 octets puisque 4octets sont reservé à la taille et au CRC16 (d'ou le -1-2-2 pour datas et -1-2-4 pour CRC32 en longword).
    [ Sources et programmes de Dr.Who | FAQ Delphi | FAQ Pascal | Règlement | Contactez l'équipe ]
    Ma messagerie n'est pas la succursale du forum... merci!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Que choisir ? C# , VB.NET, C++, Delphi ? pourquoi ?
    Par Louis-Guillaume Morand dans le forum Général Dotnet
    Réponses: 475
    Dernier message: 08/04/2010, 19h27
  2. Programmer encore en VB 6 c'est pas bien ? Pourquoi ?
    Par Nektanebos dans le forum Débats sur le développement - Le Best Of
    Réponses: 85
    Dernier message: 10/03/2009, 14h43
  3. Pourquoi ces directives #ifndef ... en haut des .h
    Par Patrick PETIT dans le forum C
    Réponses: 8
    Dernier message: 06/03/2003, 23h53
  4. Existe-t'il un type tenant sur 2 octets ?
    Par benj63 dans le forum C++Builder
    Réponses: 13
    Dernier message: 20/06/2002, 17h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo