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:
Mon appareil possède plusieurs modes:
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;
1. Télécommande n'attendant pas de réponse (ex: $34 pour éteindre l'appareil)
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 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;
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
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;
avec les procédures événementielles suivantes:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 OnRxData := EvenementSerialRxData; OnStatus := EvenementSerialStatus;
Jusqu'ici, tout va bien.
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;
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é.
En attente de vos conseils et cdlt
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;
Partager