Creation noyau d'appel

Résolu
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 - 6 mars 2010 à 12:51
Oniria Messages postés 292 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

9 réponses

Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
6 mars 2010 à 20:08
Salut,

Essaie ça :

@FProcedure := Pointer(strtoint(ListeFonction.Strings[SendIndex])); 
FProcedure;
3
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
6 mars 2010 à 21:06
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
3
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
6 mars 2010 à 14:12
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 ?
0
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
6 mars 2010 à 14:23
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.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
6 mars 2010 à 16:06
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
0
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
6 mars 2010 à 16:42
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
0
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
6 mars 2010 à 22:23
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.
0
Guillemouze Messages postés 991 Date d'inscription samedi 25 octobre 2003 Statut Membre Dernière intervention 29 août 2013 6
7 mars 2010 à 13:42
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
0
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
7 mars 2010 à 16:00
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
0
Rejoignez-nous