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

Langage C++ Discussion :

wrapper C++ pour library c


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 69
    Par défaut wrapper C++ pour library c
    Ca permet d'avoir l'implémentation que l'on souhaite donc c'est plutôt bien .
    Le problème c'est que j'ai déjà une classe que gère l'i2c pour les autres capteurs et j'aimerai bien faire appelle a elle dans cette Library
    via un wrapper. Comment puis je m'en sortir?

    voila ce que j'ai

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    namespace comm
    {
    	class I2c
    	{
    		I2c()
    		~I2C();
    		write (int x, int y, int z);
                    read(int x, int y, int z);
    	};
    }

    Les fonctions utilisée par la Libraire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    writeI2c(int x, int y, int z);
    readI2c(int x, int y, int z);
    je voulais créer un wrapper qui prennent en pointer ma class de façon a pourvoir faire ca:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    comm::I2c* ptrI2C
     
    writeI2c(int x, int y, int z)
    {
    ptrI2C->write(int x, int y, int z)
    }
     
    readI2c(int x, int y, int z)
    {
    ptrI2C-read(int x, int y, int z)
    }
    Mais je ne m'en sors pas.
    Merci par avance

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 638
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 638
    Par défaut
    Salut,
    Ben, tu n'as qu'à faire ce que tu indiques : appeler writeI2C à partir de la fonction membre write et appeler la fonction readI2C depuis la fonction read, à chaque fois en leur transmettant les paramère fournis à la fonction

    Au fait : une fonction a toujours un type de retour!!! Où ils sont les types de retour de tes fonctions write et read???

    Après, il faudra peut-être prendre en compte les politiques d'initialisation et de "nettoyage" de ta bibliothèque (car, library, ca se traduit par "bibliothèque" en francais ) I2C : la première (l'initialisation) devra sans doute être prise en charge par le constructeur de ta classe, et la deuxième (le "nettoyage") devra sans doute être pris en charge par ... le destructeur de ta classe
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 69
    Par défaut
    merci pour ta réponse,
    Effectivement ca marche, j'avais un problème de header, qui fait que la Library tirée la class d'où mon problème.

    Mais je vais quand même avoir un problème quand je voudrais inclure la Library dans mon exécutable C++. Je m'explique:

    Dans la Library j'ai donc ajouté l'include sur le header de mon wrapper cela permet de définir les fonctions read/writei2c. Pour l'instant mon pointer n'est présent que dans le .cpp. Or si je veux le setter dans mon exécutable qui a la classe I2C il faut qu'elle connaisse sa définition (il faut donc que je l'ajoute dans le header du wrapper et donc paf je me retrouve avec du code c++ tiré par la Library qui ne compile alors plus

    oui désolé j'ai écris un peu vite bien sur qu'elles ont des types de retour .
    Jai effectivement une méthode initialize() appelée dans le ctor et close membre de ma classe appelée dans le dtor mais je ne les ai pas fait apparaitre, je n'ai pas trouvé utile a mon problème .

    Je voulais en plus créer une méthode set du pointer, mais cela ne semble pas possible vu que la que la signature aura un paramètre de type class I2C.
    Qu'est ce qui est le mieux

    créer une méthode avec un paramètre void* et caster en I2C ou initialisé directement le pointer sans passer par une méthode?
    Je préfère la première car cela permet de vérifier l'état du pointer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void setI2cPtr(void* ptr)
    {
      ptrI2C = static_cast<comm::I2c*>(ptr);
    }
     
    ou directement 
     
    ptrI2C = this; // (dans la classe)

    Un avis?

    Cordialement,
    merci!!

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 638
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 638
    Par défaut
    Il serait utile que tu nous montre ton code complet, que l'on puisse travailler sur quelque chose de complet, car, tes explications ne sont pas parfaitement claires
    Jai effectivement une méthode initialize() appelée dans le ctor
    Et, dis moi: quelle est la différence entre une fonction "initialize()" et le constructeur Pourquoi ne mettrais tu pas carrément tout le contenu de ta fonction initialize() directement dans le constructeur

    Ceci dit, pourquoi crois tu que l'on travaille avec deux types de fichiers en C++ La réponse simple est que le fichier d'en-tête (*.hpp) permet simplement au compilateur de savoir que "quelque chose" existe, alors que le fichier d'implémentation (*.cpp) permet au compilateur de savoir "ce qu'il doit faire"

    Si j'ai bien compris, il faut initialiser "une bonne fois pour toutes" un (unique) pointeur vers une structure issue de la bibliothèque C Hé bien, quand on va compiler le wrapper, il n'y a que les fonctions membre de notre classe qui devront y accéder. Et, pour ce faire, rien de plus facile : nous déclarons ce pointeur uniquement dans le fichier d'implémentation . Un petit exemple pour me faire comprendre:
    Wrapper.hpp
    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
     
    #ifndef WRAPPER_HPP
    #define WRAPPER_HPP
    namespace I2C{
    class Wrapper{
    public:
        Wrapper();
        ~Wrapper();
        /* il faut nettoyer le tout lorsqu'on arrête d'utiliser la bibliothèque C */
        void shutDown();
        void read(int x, int y);
        void write(int x, int y);
    private:
        static bool willShutDown_;
    }
    }// namespace I2C
    #endif // WRAPPER_HPP
    Wrapper.cpp
    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
    #include <Wrapper.hpp>
    // pour disposer des exceptions 
    #include <stdexcept>
    // le fichier d'en-tete de la bibliothèque C
    #include <i2c.h>
    // pour pouvoir vérifier les préconditions
    #include <cassert>
    /* l'instance i2c issue de la bibliothèque  C */
        struct i2c * instance{nullptr};
    namespace I2C{
    bool Wrapper::willShutDown_ = false;
    Wrapper::Wrapper(){
        if(! instance)
            instance = i2c_init();
        if(! instance)
            throw std::runtime_error("unable to initialize i2c");
    }
    Wrapper::~Wrapper(){
        if(willShutDown_)
           i2c_destroy(instance);
    }
    /* read et write se contentent de déléguer le travail au fonctions de la bibliothèque C */
    void Wrapper::read(int x, int y){
        assert(instance && "I2C not initialized, please do it first");
       i2c_read(x, y);
    }
    void Wrapper::write(int x, int y){
        assert(instance && "I2C not initialized, please do it first");
       i2c_write(x, y);
    }
    void Wrapper::shutDown(){
        willShutDown_=true;
    }
    } // namespace I2C
    Le tout pourrait être utilisé sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <Wrapper.hpp>
    int main(){
        /* on crée une instance du wrapper, ce qui provoque l'initialisation de la bibliothèque I2C */
        Wrapper wrap;
        /* on peut écrire ou lire à partir du wrapper */
        wrap.read(10,15);
        wrap.write(50,25);
        /* quand on a fini, on indique qu'il faut nettoyer le tout */
        wrap.shutDown();
    } //les règles de portée font que notre variable wrap est détruite ici et que son destructeur est donc appelé
      // comme willShutDown_ est égal à true (après appel de la fonction shutDown), i2c_destroy est appelée
    Maintenant, je ne sais absolument rien de la bibliothèque C que tu utilises! je me suis donc contenter d'utiliser des noms qui semblaient logiques, mais qui pourraient être tout à fait différents (pour la structure et les différentes fonctions), mais le principe est malgré tout sensiblement pareil

    Pour que tout cela fonctionne, il suffira:
    1. d'ajouter le dossier dans lequel se trouve le fichier d'en-tête de la bibliothèque C lors de la compilation, sous une forme proche deg++ -c Wrapper.cpp -I. -Idossier_en-tete_i2c
    2. d'indiquer explicitement à l'éditeur de liens qu'il doit utiliser la bibliothèque C sous une forme proche deg++ -c Wrapper.o main.o -li2c -o myapp


    (je considère que la biblioithèque C est nommée libi2c.a, et j'utilise Gcc pour la compilation... à adapter à ta propre situation
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 638
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 638
    Par défaut
    Au fait, je ne sais pas si c'est cette bibliothèque que tu utilise, mais, as-tu déjà jeté un œil à la doc que l'on trouve ==>ici<==
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 69
    Par défaut
    Merci pour ta réponse

    J'utilse la method initializeI2C car je vais avoir plusieurs capteurs avec lesquels communiquer et j'aimerai n'avoir qu'une seule instance de mon controlleur I2C.
    Le probleme avec ton wrapper c'est qu'il est dans une class C++, c'est tout mon probleme si je veux appeler une de ces methodes depuis la library de mon capteur.

    Ce n'etait peut etre pas clair mais je ne veux pas toucher à l'implementation du driver (.c) si jamais il y a une nouvelle version je n'aurait pas trop de probleme ou mettre a jour
    , juste l'include de mon wrapper dans le header de la library.

    Voila comment est faite cette library (en gros)
    inv_mpu.h
    inv_mpu.c

    Dans mpu.c il ya des fonctions c qui appellent des fonctions read/writeI2c qui ne possede pas de signature dans inv_mup.h/.c
    J'ai donc creer des fichiers WrapperDriverMpu.h/.c qui implementent ces fonctions. Ces fonctions appellent alors ma class MPU6050 via un pointer
    qui appelent les methodes de l'I2c Controller.

    Concerant la library i2c je ne la conaissais pas, mais il semble que mon I2cControleur fait la meme chose mais encapsulé dans une class au lieu de fonctions

    Voila ce que j'ai fait jusqu'à présent, pour l'instance cela compile mais je ne l'ai pas encore exécuter. Si tu as des commentaires n'hésite pas
    Un point qui m'embête mais je ne pense pas avoir le choix c'est que les méthodes readMPU6050 et writeMPU6050 sont public

    WrapperMpu6050ptr.hpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #include "Mpu6050.hpp"
     
    static ::sensors::Mpu6050* ptrMpuController = 0;
     
    void setI2cControllerPtr(::sensors::Mpu6050* pMpuController);
    WrapperDriverMpu.hpp
    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
     
    #pragma once
     
    #include "inv_mpu.h"
     
    #ifdef __cplusplus
    extern "C" {
    #endif
     
    unsigned char i2c_read(unsigned char slave_addr, unsigned char reg_addr, unsigned char length, unsigned char *data);
     
    unsigned char i2c_write(unsigned char slave_addr, unsigned char reg_addr, unsigned char length, unsigned char const *data);
     
    #ifdef __cplusplus
    }
    #endif
    WrapperDriverMpu.cpp
    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
     
    #include "WrapperDriverMpu.hpp"
    #include "WrapperMpu6050ptr.hpp"
    #include <errno.h>
    #include <time.h>
     
    void setI2cControllerPtr(::sensors::Mpu6050* pMpuController)
    {
        ptrMpuController = pMpuController;
    }
     
    unsigned char i2c_read(unsigned char slave_addr, unsigned char reg_addr, unsigned char length, unsigned char *data)
    {
        ptrMpuController->readMpu6050(slave_addr, reg_addr, length, data);
    }
     
    unsigned char i2c_write(unsigned char slave_addr, unsigned char reg_addr, unsigned char length, unsigned char *data)
    {
        ptrMpuController->writeMpu6050(slave_addr, reg_addr, length, data);
    }

    MPU6050.hpp
    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
     
    namespace sensors
    {
      class Mpu6050
      {
        public:
     
          Mpu6050(::communications::i2c::I2cController& i2cController);
     
          ~Mpu6050();
     
          int8_t readMpu6050(const uint8_t& devAddr, const uint8_t& regAddr, const uint8_t& length, uint8_t* data);
     
          void writeMpu6050(const uint8_t& devAddr, const uint8_t& regAddr, const uint8_t& length, uint8_t* data);
     
          ::communications::i2c::I2cController& _rI2cController;
     
        private:
     
          uint16_t _fd{0};
     
          uint8_t _deviceAddr{0x50};
      };
    }
    MPU6050.cpp
    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
     
    namespace sensors
    {
      Mpu6050::Mpu6050(::communications::i2c::I2cController& i2cController)
        : _rI2cController(i2cController)
      {
        setI2cControllerPtr(this);
        _rI2cController.initializeI2c(_fd, _deviceAddr);
      }
     
      Mpu6050::~Mpu6050()
      {
     
      }
     
      int8_t Mpu6050::readMpu6050(const uint8_t& devAddr, const uint8_t& regAddr, const uint8_t& length, uint8_t* data)
      {
     
        std::cout << "************************************" << std::endl;
        //_rI2cController.readBytes(_fd, regAddr, length, data);
      }
     
      void Mpu6050::writeMpu6050(const uint8_t& devAddr, const uint8_t& regAddr, const uint8_t& length, uint8_t* data)
      {
        std::cout << "************************************" << std::endl;
        //_rI2cController.writeBytes(_fd, regAddr, length, data);
      }
     
    }
    I2cController.hpp
    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
     
    namespace communications
    {
      namespace i2c
      {
        class I2cController
        {
          public:
     
            I2cController();
     
            ~I2cController();
     
            int8_t readBytes(uint16_t& fd, const uint8_t& regAddr, const uint8_t& length, uint8_t* data);
     
            int8_t writeBytes(uint16_t& fd, const uint8_t& regAddr, const uint8_t& length, uint8_t* data);
     
            void initializeI2c(uint16_t& fd, const uint8_t& devAddr);
     
            void closeI2c(uint16_t& fd);
        };   
      }
    }
    I2cController.cpp
    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
     
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <cstdint>
    #include <unistd.h>
    #include <string.h>
    #include <linux/i2c-dev.h>
     
    #include "I2cController.hpp"
     
     
    namespace communications
    {
      namespace i2c
      {
     
        I2cController::I2cController()
        {
     
        }
     
        I2cController::~I2cController()
        {
     
        }
     
        void I2cController::initializeI2c(uint16_t& fd, const uint8_t& devAddr)
        {
          fd = open("/dev/i2c-1", O_RDWR);
     
          if(fd < 0)
          {
            //LOG_ERROR("I2cController :: readBytes() Failed to open device");
            return;
          }
     
          if (ioctl(fd, I2C_SLAVE, devAddr) < 0)
          {
              //LOG_ERROR("I2cController :: readBytes() Failed to select device"); 
              close(fd);
              return;
          }
        }
     
        int8_t readBytes(uint16_t& fd, const uint8_t& regAddr, const uint8_t& length, uint8_t* data)
        {
            int8_t count = 0;
            if (write(fd, &regAddr, 1) != 1) 
            {
                //LOG_ERROR("I2cController :: readBytes() Failed to write reg"); 
                close(fd);
                return(-1);
            }
            count = read(fd, data, length);
            if (count < 0) 
            {
                //LOG_ERROR("I2cController :: readBytes() Failed to read device");
                close(fd);
                return(-1);
            } else if (count != length)
            {
                //LOG_ERROR("I2cController :: readBytes() Short read from device");
                close(fd);
                return(-1);
            }
        }
     
        int8_t writeBytes(uint16_t& fd, const uint8_t& regAddr, const uint8_t& length, uint8_t* data)
        {
            int8_t count = 0;
            uint8_t buf[128];
     
            buf[0] = regAddr;
            memcpy(buf+1,data,length);
            count = write(fd, buf, length+1);
            if (count < 0) {
                //LOG_ERROR("I2cController :: writeBytes() Failed to write device"); 
                close(fd);
                return(-1);
            } else if (count != length+1) {
                //LOG_ERROR("I2cController :: writeBytes() Short write to device");
                close(fd);
                return(-1);
            }
        }
     
        void I2cController::closeI2c(uint16_t& fd)
        {
          close(fd);
        }
     
      }
    }

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

Discussions similaires

  1. Problème pour library caml
    Par magnum1506 dans le forum Caml
    Réponses: 2
    Dernier message: 29/01/2010, 07h59
  2. Wrapper GLScene pour Purebasic
    Par Newbie1 dans le forum PureBasic
    Réponses: 1
    Dernier message: 13/10/2009, 22h31
  3. Réponses: 5
    Dernier message: 07/06/2009, 13h46
  4. [JNA] Faire un wrapper java pour une application C
    Par danim dans le forum Entrée/Sortie
    Réponses: 9
    Dernier message: 30/10/2008, 16h04
  5. [Interop] Wrapper .NET pour les API Windows ?
    Par tomlev dans le forum C++/CLI
    Réponses: 3
    Dernier message: 31/03/2008, 10h31

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