Bjr à tous et félicitations à Jurassik Pork pour son composant TLazSerial.

Un petit souci: Lorsque je perds ma connexion COM, un 'freeze' se produit lors des tentatives de lecture/écriture.

Peut-on spécifier un 'timeout' (un setter de la forme TLazserial.SetTimeout(const Delay: integer) ) ?

Est-il possible de forcer la clôture d'une connexion ?

Y a-t-il un exemple complet d'utilisation ?


Je dispose d'un appareil (lasermètre DistoX) raccordé en Bluetooth (considéré comme un port série RS232C)
Une classe métier TPilotageDistoX dérive de TLazSerial

Ouverture et fermeture de la connexion de mon DistoX:
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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 
function TPilotageDistoX.OpenDistoXConnexion(): boolean;
begin
  Application.ProcessMessages;
  //FDistoXMustBeReady := false;
  Result := false;
  AfficherMessage(Format('%s.OpenLazSerial: %s', [ClassName, self.Device]));
  Result := False;
  FCalibrationModeON := False;
  FLaserON           := False;
  FModeAttenteDonneesRX := mrxNONE;
  oldtype  := 0;
  oldX     := 0;
  oldY     := 0;
  oldZ     := 0;
  SetTimeoutDelay(10000);
 
  // TLazserial présumé fonctionner sur Win et Linux
  try
    self.OnRxData      := EvenementSerialRxData;
    self.Active        := true;
    Result             := self.Active; // ouverture de la connexion. Ne pas utiliser self.Open et consorts
  except
    on E: Exception do AfficherMessageErreur(Format('Connexion sur port "%s" impossible' + #13#10 + 'Message: %s',
          [self.Device, E.Message]));
  end;
end;
 
procedure TPilotageDistoX.CloseDistoXConnexion();
begin
  AfficherMessage(Format('%s.CloseLazSerial', [ClassName]));
  Application.ProcessMessages;
  oldtype  := 0;
  oldX     := 0;
  oldY     := 0;
  oldZ     := 0;
 
  try
    FModeAttenteDonneesRX := mrxNONE;
    FCalibrationModeON := False;
    FLaserON           := False;
    FDistoXSerialNumber    := -1;
    FDistoXVersionHardware := -1;
    FDistoXVersionFirmware := -1;
    self.Active := false;
  finally
  end;
end;
Mon appareil possède plusieurs modes:
1. Télécommande n'attendant pas de réponse (ex: $34 pour éteindre l'appareil)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
 
procedure TPilotageDistoX.ExtinctDevice();
var
  EWE: byte;
begin
  Application.ProcessMessages;
  AfficherMessage(Format('%s.ExtinctDevice', [ClassName]));
  // Valeur de la commande d'extinction: 00110100
  EWE := DISTOX_COMMAND_EXTINCTION;//  $34;
  self.WriteByteOfData(EWE);
  self.CloseDistoXConnexion();
end;
2. Interrogation de l'appareil: lecture directe de valeurs
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
25
26
27
28
29
 
// numéro de série du DistoX
function TPilotageDistoX.ExtractNumSerieFromDistoX(): integer;
var
  MyBuffer: TDistoXDataBuffer; // TDistoXDataBuffer = array[0..7] of byte
begin
  Application.ProcessMessages;
  // FDistoXSerialNumber est initialisé à -1 dans l'initialisateur; s'il est positif ou nul, c'est que le numéro de série a déjà été obtenu
  //                                                                               dans ce cas, on ne fait rien, sinon on procède à une nouvelle demande
  if (FDistoXSerialNumber = -1) then          
  begin
    if (ReadBufferAtAddress($8008, MyBuffer)) then  FDistoXSerialNumber := MyBuffer[3] + MyBuffer[4] shl 8; // retourne 2395 ou 2329 pour les DistoX de JPC
  end;
  Result := FDistoXSerialNumber;
end;
// version de firmware
function TPilotageDistoX.ExtractVersionFirmWareFromDistoX(): integer;
var
  MyBuffer: TDistoXDataBuffer;
begin
  Application.ProcessMessages;
  // FDistoXVersionFirmware est initialisé à -1 dans l'initialisateur; s'il est positif ou nul, c'est que le numéro de firmware a déjà été obtenu
  //                                                                                   dans ce cas, on ne fait rien, sinon on procède à une nouvelle demande
  if (FDistoXVersionFirmware = -1) then     // si FDistoXVersionFirmware = - 1, on fait une tentative d'extraction;
  begin
    if (ReadBufferAtAddress($E000, MyBuffer)) then FDistoXVersionFirmware := 100 * MyBuffer[3] + MyBuffer[4];
  end;
  Result := FDistoXVersionFirmware;
end;
3. Armement d'un état: on positionne un drapeau FModeAttenteDonneesRX et on travaille avec les événements définis dans l'initialisateur de TPilotageDistoX:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
 
  OnRxData := EvenementSerialRxData;
  OnStatus := EvenementSerialStatus;
avec les procédures événementielles suivantes:
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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 
//..............
procedure TPilotageDistoX.EvenementSerialRxData(Sender: TObject);
begin
  case FModeAttenteDonneesRX of
    mrxNONE            : ;
    mrxDEPILAGE_MESURE : self.LireEtDepilerTrameDe8OctetsData(); // lecture de 8 octets
  end;
end;
 
procedure TPilotageDistoX.EvenementSerialStatus(Sender: TObject; Reason: THookSerialReason; const Value: string);
begin
  case Reason of
    HR_SerialClose : AfficherMessage('EvenementSerialStatus: Port ' + Value + ' closed');
    HR_Connect     : AfficherMessage('EvenementSerialStatus: Port ' + Value + ' connected');
    HR_Wait        : AfficherMessage('EvenementSerialStatus: Wait : ' + Value);
  end ;
end;  
 
function TPilotageDistoX.LireEtDepilerTrameDe8OctetsData(): boolean;
var
  MyBuffer: TDistoXDataBuffer; //array[0..7] of Byte;
  // ...
begin
  Application.ProcessMessages;
  Result := False;
  try
     MyBuffer := MakeBufferVierge();                                 // initialiser avec des zéros
     if (FModeAttenteDonneesRX = mrxNONE) then Exit;        // si le mode d'acquisition continue est désarmé, quitter
 
     ...
     // lire 8 octets - TODO: version à valider
     self.ReadBuffer8bytes(MyBuffer);
     //----------------
     qtype := MyBuffer[0];
     op    := (qtype and $3F); // extraction de la nature de données
     // acquitter bonne réception et vider la première visée de la file du DistoX
     self.WriteByte((qtype  and $80) or $55) = 0); //Acknowledge(qtype);
 
     // Ce sont des données ?
     if (op < $20) then
     begin
       // ... traitement
       end;
     end;
   except
     ;
   end;  
end;
Jusqu'ici, tout va bien.

Maintenant, je dois lire des plages de la mémoire de mon appareil , notamment la zone de données contenant les mesures.
J'utilise un seul appel de la fonction ReadDataSection(const NumBlockDebut, NumBlockFin: integer): integer;
avec:
NumBlockDebut: Numéro de block de début
NumBlockFin : Numéro de block de fin

Cà marche mais c'est très lent et saccadé.

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
 
//******************************************************************************
// lecture de la zone de données
function TPilotageDistoX.ReadDataSection(const NumBlockDebut, NumBlockFin: integer): integer;
const
  NB_BLOCKS   = 19;
  NB_SEGMENTS = 56;
var
  AdresseDataZone: Integer;
  QNumBlock: Integer;
  NbDataToRead: Integer;
  NbDataAlreadyRead: Integer;
  NbStart: Integer;
  procedure LireUneVisee(const QBlock, QSegment: integer; const QAddressDebutVisee: word);
  var
    MyTrame  : TDistoXDataBuffer;
    MyBuffer1: TDistoXDataBuffer;
    MyBuffer2: TDistoXDataBuffer;
    i: Integer;
    EWE: String;
    myMesureVisee: TMesureViseeDistoX;
  begin
    // on boucle tant que la lecture des paquets n'a pas réussi
    while (not ReadAnPacket(QAddressDebutVisee, MyBuffer1)) do
      ;
    while (not ReadAnPacket(QAddressDebutVisee + 4, MyBuffer2)) do
      ;
    // construction des trames
    for i := 0 to 3 do MyTrame[i]   := MyBuffer1[3+i];
    for i := 0 to 3 do MyTrame[i+4] := MyBuffer2[3+i];
    EWE := MakeContentBuffer(MyTrame);
    // construction de la visée
    myMesureVisee := MakeTMesureViseeDistoXFromDataBuffer(QBlock, QSegment,MyTrame);
    AfficherMessage(Format('%d: %d:%d: L = %.3f m; Az = %.2f; P = %.2f - EWE = %s',
                                     [0,
                                      myMesureVisee.Block, myMesureVisee.Segment,
                                      myMesureVisee.Longueur,
                                      myMesureVisee.Azimut,
                                      myMesureVisee.Pente,
                                      myMesureVisee.HexaData
                                      ]));
    AddMesureVisee(myMesureVisee);
 
 
  end;
  // Un segment contient 18 octets mais seuls les 8 premiers contiennent une visée
  procedure LireUnSegment(const AddressBlock: word; const NumeroBlock, NumeroSegment: integer);
  var
    MyAddressSegment: Integer;
  begin
    MyAddressSegment := AddressBlock + 18 * NumeroSegment;
    // lecture de la visée
    LireUneVisee(NumeroBlock, NumeroSegment, MyAddressSegment);
    // le reste du segment est ignoré
    Application.ProcessMessages;
 
  end;
  // Un block a une taille de 1024 octets
  procedure LireUnBlock1024(const NumeroBlock: integer);
  var
    QNumSegment: Integer;
    T0, T1, dT: TDateTime;
    WU : String;
    EWE: String;
  begin
    for QNumSegment := 0 to NB_SEGMENTS - 1 do
    begin
      T0 := Now();
      LireUnSegment(1024 * NumeroBlock, NumeroBlock, QNumSegment);
      T1 := Now();
      dT := T1 - T0;
      if (Assigned(FProcAfficherProgression)) then
      begin
        // estimation du temps restant
        EWE := TimeToStr(dT * (NbDataToRead - NbDataAlreadyRead));
        WU  := Format('Block %d/%d  - Segment: %d/%d - Temps restant: %s', [NumeroBlock + 1, NB_BLOCKS,
                                                                            QNumSegment + 1, NB_SEGMENTS,
                                                                            EWE]);
        FProcAfficherProgression(WU, NbStart, NbDataToRead, NbDataAlreadyRead);
        NbDataAlreadyRead += 1;
      end;
    end;
  end;
begin
  Result := -1;
  if (not self.Active) then Exit;
  AdresseDataZone := $0;
  NbStart := 0;
  NbDataAlreadyRead := 0;
  NbDataToRead := (1 + NumBlockFin - NumBlockDebut) * NB_SEGMENTS;
  Application.ProcessMessages;
  AfficherMessage(Format('%s.ReadMemoryArea(%X)', [ClassName, AdresseDataZone]));
  try
    for QNumBlock := NumBlockDebut to NumBlockFin do //NB_BLOCKS - 1 do
    begin
      AfficherMessage('-----------------------------------------------');
      LireUnBlock1024(QNumBlock);
    end;
  except
    ; //AfficherMessageErreur('*** Transfert arrêté par l''utilisateur');
  end;
end;
En attente de vos conseils et cdlt