Creation noyau d'appel [Résolu]

Messages postés
296
Date d'inscription
dimanche 14 mars 2004
Statut
Membre
Dernière intervention
18 décembre 2014
- - Dernière réponse : Oniria
Messages postés
296
Date d'inscription
dimanche 14 mars 2004
Statut
Membre
Dernière intervention
18 décembre 2014
- 7 mars 2010 à 16:00
Bonjour à tous,

Je vous écris pour vous demander de l'aide sur une question dont je ne trouve pas la réponse.

J'aimerais faire un noyau d'appel de procedure.
Je m'explique plus précisément : Je veux faire une application qui permettra de diagnostiquer des voitures en utilisant le port série.

J'aimerais créer un noyau qui se chargera de la communication en fonction de ce qu'on lui demande d'envoyer sur le port série.
Par exemple, j'aurais une fenetre dont l'utilisateur mettra par exemple, je veux voir le régime du moteur, la fenetre appelle une fonction "surveillance" avec comme parametre le message permettant de lire le régime moteur ainsi que l'adresse de la fonction à appeler lorsque le calculateur aura répondu à cette requéte.
La fonction "surveillance" recevra ainsi une liste de message à envoyer et une liste de fonction à appeler.C'est cette fonction qui gérera l'envoi des message et la réception.
Mais attention, les procedure ne se trouverons pas toutes dans la même unité.
Ce que je sais pas faire : c'est comment extraire l'adresse d'une fonction et comment appeler une fonction par son adresse de manière dynamique.

Un grand merci à ceux qui pourront m'aider


Oniria
Afficher la suite 

9 réponses

Meilleure réponse
Messages postés
2527
Date d'inscription
jeudi 15 janvier 2004
Statut
Membre
Dernière intervention
16 octobre 2019
13
3
Merci
Salut,

Essaie ça :

@FProcedure := Pointer(strtoint(ListeFonction.Strings[SendIndex])); 
FProcedure;

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources 187 internautes nous ont dit merci ce mois-ci

Commenter la réponse de Caribensila
Messages postés
296
Date d'inscription
dimanche 14 mars 2004
Statut
Membre
Dernière intervention
18 décembre 2014
2
3
Merci
Merci profondément Caribensala, ca marche super bien, je viens d'essayer avec une appli tout ce qu'il y a de plus simple :

un bouton Button1 sur une fiche et lorsque l'on appui sur le bouton, le texte du bouton se change en 'OK' le source est le suivant :

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Déclarations privées }
Liste : TStringList;
FProcedure : Procedure;
public
{ Déclarations publiques }

end;

procedure view;

var
Form1: TForm1;



implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
Liste:=TStringList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
Liste.Free;
end;

procedure view;
begin
Form1.Button1.Caption:='OK';
end;

procedure TForm1.Button1Click(Sender: TObject);
var i : integer;
begin
Liste.Clear;
i:=Integer(@View);
Liste.Add(inttostr(i));
@Form1.FProcedure:=Pointer(strtoint(Liste.Strings[0]));
Form1.FProcedure;
end;

end.

Ce qui est interressant c'est le Button1click.

Ce n'est qu'un exemple mettant en oeuvre ce que je voulais.
Donc j'initialise la liste qui va contenir l'adresse de la procedure à lancer. Le transtypage permet de convertir la valeur Pointer en Integer.
Ensuite, cet entier i, je le place dans ma liste.

Puis je fais ce que Caribensala m'a conseillé, transtyper à nouveau l'entier sorti de la liste en Pointer.
Puis on lance la procedure.
Et dans mon cas, ca a marché nickel.

Un gros merci à foxi et Caribensala. Ca m'enléve une super épine du pied.


Oniria

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources 187 internautes nous ont dit merci ce mois-ci

Commenter la réponse de Oniria
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26
0
Merci
ok,

si j'ai bien compris, par exemple tu as :

une methode pour récuperer :
RPM sur peugeot 307, RPM sur peugeot 3008, RPM sur renault Safrane 2009 etc.

donc au moins 3 commandes différente.
ou 3 ordinateurs de bord différent.

et donc, ta méthode GetRPM (exemple) doit pouvoir renvoyer le bonne commande selon le modèle d'ordinateur de bord.

c'est ça ?
Commenter la réponse de f0xi
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26
0
Merci
je pense que le mieux serait de definir une classe "ordinateur de bord" (TOnboardComputerCar) et de classifier les modéles de commande selon ce dernier.

exemple bateau :
unit OCC;

interface

type
  TOnboardComputerCar = class
  private
    fModelOCC : LongWord;
  public
    property ModelOCC : LongWord read fModelOCC write fModelOCC;
  end;

var
  OnboardComputerCar : TOnboardComputerCar;

implementation
 
uses
  UPeugeot, URenault, UCitroen, UNissan, UMercedes, UBmw, UAudi;

function TOnboardComputerCar.GetRPM: single;
begin
  case fModelOCC of
    PEUG_MK300 : result := UPeugeot.MK300GetRPM;
    PEUG_ML600 : result := UPeugeot.ML600GetRPM;
    REUN_LV530 : result := UReunault.LV530GetRPM;
    CITR_CC4000: result := UCitroen.CC4000GetRPM;
    NISS_NS1SKL: result := UNissan.NS1SKLGetRPM;
    else
      result := 0.0;
  end;
end;

initialization
  OnboardComputerCar := TOnboardComputerCar.Create;

finalization
  OnboardComputerCar.Free;

end.


ou encore avec un modéle de classe compléte pour chaque ordinateur de bord, genre TCollectionItem/TCollection etc.
Commenter la réponse de f0xi
Messages postés
296
Date d'inscription
dimanche 14 mars 2004
Statut
Membre
Dernière intervention
18 décembre 2014
2
0
Merci
Bonjour,

Merci d'avoir répondu foxi. Ce n'est pas ce que je veux faire. Je me suis mal expliqué.

Voila, je veux faire un composant qui s'appelle Dialogue qui serait défini en gros comme ca :

unit uDialogue;

interface

uses Windows, SysUtils, Classes, Graphics, Forms, Controls,
StdCtrls, Messages, ExtCtrls, ComCtrls,Cport;

type
TDialogue = class(TComponent)
private
{ Déclarations privées }
SendIndex : integer;
ListeCde : TStringList;
ListeFonction : TStringList;
Timer_Cadence : TTimer;
FComport : TComport;
procedure FComPortRxChar(Sender: TObject; Count: Integer);
procedure Timer_CadenceTimer(Sender: TObject);
public
{ Déclarations publiques }
constructor Create(AOwner : TComponent);override;
destructor Destroy; override;
function init : boolean;
function addDialogue(var commande : string; adresse : string) : integer;
function DeleteDialogue(Number : integer) : boolean;
end;

var
Dialogue: TDialogue;
implementation

{ TDialogue }

function TDialogue.addDialogue(var commande: string;
adresse: string): integer;
begin
ListeCde.Add(Commande);
ListeFonction.Add(adresse);
end;

constructor TDialogue.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Timer_Cadence:=TTimer.Create(Self);
Timer_Cadence.OnTimer:=Timer_CadenceTimer;
FComport:=TComport.Create(Self);
FComport.OnRxChar:=FComPortRxChar; // On associe ma fonction de réception avec celle du composant comport
SendIndex:=0;
Timer_Cadence.Enabled:=False;
end;

function TDialogue.DeleteDialogue(Number: integer): boolean;
begin
ListeCde.Delete(Number);
ListeFonction.Delete(Number);
if ListeCde.Count=0 then Timer_Cadence.Enabled:=False;
end;

destructor TDialogue.Destroy;
begin
ListeCde.Free;
ListeFonction.Free;
inherited;
end;

procedure TDialogue.FComPortRxChar(Sender: TObject; Count: Integer);
var texte : string;
begin
// réception des données
// a la réception des données, je construit la trame et je l'envoi à la fonction qui en a besoin
if ListeCde.Count=0 then Timer_Cadence.Enabled:=False;
FComport.ReadStr(texte,Count);

appelFonction(ListeFonction.Strings[i]);
// C'est ca que je ne sais pas faire, appeler une fonction directement par son adresse
end;

function TDialogue.init: boolean;
begin
// initialisation
ListeCde.Clear;
ListeFonction.Clear;
Timer_Cadence.Enabled: =False;
end;

procedure TDialogue.Timer_CadenceTimer(Sender: TObject);
begin
// On envoie la commande suivante
If ListeCde.Count=0 then
begin
Timer_Cadence.Enabled:=False;
exit;
end;
SendIndex:=SendIndex+1;
if SendIndex>=ListeCde.Count then SendIndex:=0;
FComport.WriteStr(ListeCde.Strings[SendIndex]);
end;

end.

Dans le programme principal, je vais avoir par exemple un bouton 1 qui lorsque l'on appui dessus va
Appeler Dialogue.AddDialogue('12 01 56', @VisualisationGraphique);

Si on appui sur le bouton 2, il va appeler par exemple

Dialogue.AddDialogue('21 03 59', @VisualisationTexte);

et ainsi de suite.

C'est le composant dialogue qui va appeler directement les fonction VisualisationGraphique et visualisationtexte en fonction de la commande qu'il a envoyé.

L'interet vient du fait que je pourrais ainsi mettre à jour des fenêtres différentes sans me soucier de quoi que ce soit. Ca va me simplifier grandement la vie.

Merci encore de prendre du temps pour me répondre

Cordialement

Oniria
Commenter la réponse de Oniria
Messages postés
296
Date d'inscription
dimanche 14 mars 2004
Statut
Membre
Dernière intervention
18 décembre 2014
2
0
Merci
J'ai testé plusieurs chose et ca ne fonctionne pas.

J'ai déclaré une variable comme ceci : FProcedure : Procedure;

ListeFonction.Strings[SendIndex] contient l'adresse de la fonction a appeler.

Puis pour l'appel j'ai fait :

@FProcedure:=strtoint(ListeFonction.Strings[SendIndex]);
FProcedure;

Ca ne marche pas car il me dit qu'un pointeur n'est pas compatible avec un entier.

J'aimerais bien controler l'adresse de cette procedure. Et comment stoquer l'adresse sous forme de string ????

Merci à tous


Oniria
Commenter la réponse de Oniria
Messages postés
2527
Date d'inscription
jeudi 15 janvier 2004
Statut
Membre
Dernière intervention
16 octobre 2019
13
0
Merci
Ravi que ça puisse t'aider, Oniria. :)

Au passage, les transtypages Integer -> Pointer et Pointer -> Integer permettent aussi de faire des trucs très utiles avec le Tag des compos (qui sont des Integers, donc des pointeurs en puissance).
Je te laisse explorer cette possibilité très intéressante aussi.
Commenter la réponse de Caribensila
Messages postés
1015
Date d'inscription
samedi 25 octobre 2003
Statut
Membre
Dernière intervention
29 août 2013
5
0
Merci
Un petit complement a la reponse de cari:

interface

type
  TToto = class
  public
    function ObjTest(AParam: integer): boolean;
  end;

function GlobTest(AParam: integer): boolean;

//Tu ne pourra pas utiliser ces 2 fonctions avec un même type de variable
type
  TGlobFunc = function(AParam: integer): boolean; //pour les fonctions globales
  TObjFunc = function(AParam: integer): boolean of object;//pour les fonctions d'objets
...
var
  objFunc: TObjFunc;
  globFunc: TGlobFunc;
begin
  objFunc := @MyToto.ObjTest; //ok
  objFunc := @GlobTest; //pas ok
  globFunc := @MyToto.ObjTest; //pas ok
  globFunc := @GlobTest; //ok


Moralité, n'oublies pas le "of object" si les procedures que tu memorise appartiennent a des objets
Commenter la réponse de Guillemouze
Messages postés
296
Date d'inscription
dimanche 14 mars 2004
Statut
Membre
Dernière intervention
18 décembre 2014
2
0
Merci
Merci à vous deux, Je ne savait pas que suivant le type de procedure ( dans un objet ou pas) il y avait une différence. Je vais devoir me méfier

Je vais devoir m'y mettre sérieusement maintenant. Le programme que je veux faire va être très imposant car il doit permettre d'analiser ce qui se passe sur les lignes de diagnostique mais aussi, emmettre des trames, simuler des calculateurs etc...

J'en ai au moins pour six mois de boulot mais le jeux en vaut la chandelle...

Bon week end et bon codage...


Oniria
Commenter la réponse de Oniria