diff --git a/src/SocExplorerEngine/SocExplorerEngine.pro b/src/SocExplorerEngine/SocExplorerEngine.pro --- a/src/SocExplorerEngine/SocExplorerEngine.pro +++ b/src/SocExplorerEngine/SocExplorerEngine.pro @@ -133,7 +133,9 @@ HEADERS += \ engine/socexplorersettings.h \ engine/socexplorersettingsdialog.h \ engine/socexplorergui.h \ - engine/socexplorerconfigkeys.h + engine/socexplorerconfigkeys.h \ + pluginsInterface/isocexplorerplugin.h \ + pluginloaderV2/pluginmanager.h @@ -166,7 +168,8 @@ SOURCES += \ PeripheralWidget/src/collapsableperipheralwidget.cpp \ engine/socexplorersettings.cpp \ engine/socexplorersettingsdialog.cpp \ - engine/socexplorergui.cpp + engine/socexplorergui.cpp \ + pluginloaderV2/pluginmanager.cpp OTHER_FILES += \ diff --git a/src/SocExplorerEngine/pluginloader/pluginloader.cpp b/src/SocExplorerEngine/pluginloader/pluginloader.cpp --- a/src/SocExplorerEngine/pluginloader/pluginloader.cpp +++ b/src/SocExplorerEngine/pluginloader/pluginloader.cpp @@ -217,69 +217,6 @@ socexplorerplugin* pluginloader::newsoce #endif } - -QString pluginloader::getlibTypeStr(QString Name) -{ - if(_self==NULL)init(); - QString* libfile= _cacheLookup(Name); - if(libfile==NULL)return NULL; - QLibrary* lib = new QLibrary(*libfile); - delete libfile; - lib->load(); - if(lib->isLoaded()) - { - socexplorerpluginTypeT plugintype = (socexplorerpluginTypeT)lib->resolve("socexplorerpluginType"); - if(plugintype!=NULL) - { - pluginT type = plugintype(); - switch(type) - { - case ComDriverT: - ////lib->unload(); - lib->~QLibrary(); - return QObject::tr("Comunaication Driver Plugin."); - break; - case PerifDriverT: - ////lib->unload(); - lib->~QLibrary(); - return QObject::tr("Periferial Driver Plugin."); - break; - default: - ////lib->unload(); - lib->~QLibrary(); - return QObject::tr("Unknow Plugin."); - break; - } - } - } - lib->~QLibrary(); - return QObject::tr("Can't load Plugin."); -} - - - - -pluginT pluginloader::getlibType(QString Name) -{ - if(_self==NULL)init(); - QString* libfile= _cacheLookup(Name); - if(libfile==NULL)return (pluginT)NULL; - QLibrary* lib = new QLibrary(*libfile); - delete libfile; - lib->load(); - if(lib->isLoaded()) - { - socexplorerpluginTypeT plugintype = (socexplorerpluginTypeT)lib->resolve("socexplorerpluginType"); - if(plugintype!=NULL) - { - return plugintype(); - } - } - lib->~QLibrary(); - return -1; -} - - QString pluginloader::getlibVersion(const QString Name) { if(_self==NULL)init(); diff --git a/src/SocExplorerEngine/pluginloader/pluginloader.h b/src/SocExplorerEngine/pluginloader/pluginloader.h --- a/src/SocExplorerEngine/pluginloader/pluginloader.h +++ b/src/SocExplorerEngine/pluginloader/pluginloader.h @@ -59,8 +59,6 @@ public: static int checklibrary(const QString fileName); static bool isvalid(QString Name); static socexplorerplugin* newsocexplorerplugin(const QString Name); - static QString getlibTypeStr(QString Name); - static pluginT getlibType(QString Name); static QString getlibVersion(const QString Name); static QString getlibPIDstr(const QString Name); static QString getlibVIDstr(const QString Name); diff --git a/src/SocExplorerEngine/pluginloaderV2/pluginmanager.cpp b/src/SocExplorerEngine/pluginloaderV2/pluginmanager.cpp new file mode 100644 --- /dev/null +++ b/src/SocExplorerEngine/pluginloaderV2/pluginmanager.cpp @@ -0,0 +1,117 @@ +/*------------------------------------------------------------------------------ +███████╗ ██████╗ ██████╗ ███████╗██╗ ██╗██████╗ ██╗ ██████╗ ██████╗ ███████╗██████╗ +██╔════╝██╔═══██╗██╔════╝ ██╔════╝╚██╗██╔╝██╔══██╗██║ ██╔═══██╗██╔══██╗██╔════╝██╔══██╗ +███████╗██║ ██║██║ █████╗ ╚███╔╝ ██████╔╝██║ ██║ ██║██████╔╝█████╗ ██████╔╝ +╚════██║██║ ██║██║ ██╔══╝ ██╔██╗ ██╔═══╝ ██║ ██║ ██║██╔══██╗██╔══╝ ██╔══██╗ +███████║╚██████╔╝╚██████╗ ███████╗██╔╝ ██╗██║ ███████╗╚██████╔╝██║ ██║███████╗██║ ██║ +╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ + +-- This file is a part of the SOC Explorer Software +-- Copyright (C) 2018, Plasma Physics Laboratory - CNRS +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-------------------------------------------------------------------------------*/ +/*-- Author : Alexis Jeandet +-- Mail : alexis.jeandet@lpp.polytechnique.fr +----------------------------------------------------------------------------*/ + +#include "pluginmanager.h" +#include +#include +#include +#include + +void PluginManager::loadPluginMetaData(const QString &pluginPath) +{ + if(!this->plugins_metada_cache.contains(pluginPath)) + { + if (QLibrary::isLibrary(pluginPath)) + { + QPluginLoader pluginLoader{pluginPath}; + if(pluginLoader.isLoaded()) + { + auto metadata = pluginLoader.metaData().value("MetaData").toObject(); + for (auto key:pluginKeys::all) + { + if(metadata.contains(key)) + this->plugins_metada_cache[pluginPath][key] = metadata.value(key).toString(); + } + } + + } + } +} + +bool PluginManager::isPlugin(const QString &pluginPath)const +{ + if(!this->plugins_metada_cache.contains(pluginPath)) + { + if (QLibrary::isLibrary(pluginPath)) + { + QPluginLoader pluginLoader{pluginPath}; + if(pluginLoader.isLoaded()) + { + return true; + } + } + } + return false; +} + + +PluginManager::PluginManager(const QStringList &folderList) + :folderList(folderList) +{ + scanFolders(); +} + +ISocexplorerPlugin *PluginManager::makeInstance(const QString& pluginName) +{ + auto plugin = resolvePluginName(pluginName); + if (QLibrary::isLibrary(plugin)) + { + QPluginLoader pluginLoader{plugin}; + if (auto pluginInstance = qobject_cast(pluginLoader.instance())) { + return pluginInstance; + } + } + return Q_NULLPTR; +} + + +void PluginManager::scanFolders() +{ + QDir dir; + QStringList filters{"*.so", "*.dll"}; + pluginTable.clear(); + for(auto&& folder:folderList) + { + dir.setPath(folder); + dir.setFilter(QDir::Files); + dir.setNameFilters(filters); + QFileInfoList list = dir.entryInfoList(); + for (auto&& fileInfo:list) + { + auto path = fileInfo.filePath(); + SocExplorerEngine::message("pluginloader::scanFolders","Checking "+ path,3); + if(isPlugin(path)) + { + loadPluginMetaData(path); + auto name = plugins_metada_cache[path][pluginKeys::Name]; + pluginTable[name].append(path); + } + } + } +} diff --git a/src/SocExplorerEngine/pluginloaderV2/pluginmanager.h b/src/SocExplorerEngine/pluginloaderV2/pluginmanager.h new file mode 100644 --- /dev/null +++ b/src/SocExplorerEngine/pluginloaderV2/pluginmanager.h @@ -0,0 +1,122 @@ +/*------------------------------------------------------------------------------ +███████╗ ██████╗ ██████╗ ███████╗██╗ ██╗██████╗ ██╗ ██████╗ ██████╗ ███████╗██████╗ +██╔════╝██╔═══██╗██╔════╝ ██╔════╝╚██╗██╔╝██╔══██╗██║ ██╔═══██╗██╔══██╗██╔════╝██╔══██╗ +███████╗██║ ██║██║ █████╗ ╚███╔╝ ██████╔╝██║ ██║ ██║██████╔╝█████╗ ██████╔╝ +╚════██║██║ ██║██║ ██╔══╝ ██╔██╗ ██╔═══╝ ██║ ██║ ██║██╔══██╗██╔══╝ ██╔══██╗ +███████║╚██████╔╝╚██████╗ ███████╗██╔╝ ██╗██║ ███████╗╚██████╔╝██║ ██║███████╗██║ ██║ +╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ + +-- This file is a part of the SOC Explorer Software +-- Copyright (C) 2018, Plasma Physics Laboratory - CNRS +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-------------------------------------------------------------------------------*/ +/*-- Author : Alexis Jeandet +-- Mail : alexis.jeandet@lpp.polytechnique.fr +----------------------------------------------------------------------------*/ +#ifndef PLUGINLOADER_H +#define PLUGINLOADER_H +#include +#include +#include + +template +auto loadMetadata(const QString& name, const QString &pluginName,const QHash>& plugins_metada_cache); + +template<> +auto loadMetadata(const QString& name, const QString &pluginName,const QHash>& plugins_metada_cache) +{ + if(plugins_metada_cache.contains(pluginName)) + { + return plugins_metada_cache[pluginName][name]; + } + return QString(); +} + +template<> +auto loadMetadata(const QString& name, const QString &pluginName,const QHash>& plugins_metada_cache) +{ + if(plugins_metada_cache.contains(pluginName)) + { + return plugins_metada_cache[pluginName][name].toInt(); + } + return -1; +} + +template<> +auto loadMetadata(const QString& name, const QString &pluginName,const QHash>& plugins_metada_cache) +{ + if(plugins_metada_cache.contains(pluginName)) + { + return bool(plugins_metada_cache[pluginName][name].toInt()); + } + return false; +} + +namespace pluginKeys +{ + const auto Name=QStringLiteral("Name"); + const auto Author=QStringLiteral("Author"); + const auto Version=QStringLiteral("Version"); + const auto Description=QStringLiteral("Description"); + const auto CanBeRoot=QStringLiteral("root"); + const auto CanBeChild=QStringLiteral("child"); + const auto VID=QStringLiteral("VID"); + const auto PID=QStringLiteral("PID"); + + const auto all={Name, Author, Version, Description, CanBeRoot, CanBeChild, VID, PID}; +}; + +class PluginManager +{ + void loadPluginMetaData(const QString &pluginPath); + bool isPlugin(const QString &pluginPath)const; + + QString resolvePluginName(const QString &pluginName)const + { + if( plugins_metada_cache.contains(pluginName)) + return pluginName; + else if (pluginTable.contains(pluginName)) { + return pluginTable[pluginName].last(); + } + return QString(); + } +public: + PluginManager(const QStringList& folderList); + ISocexplorerPlugin* makeInstance(const QString &pluginName); + +#define METADATA_GETTER(type, name)\ + type plugin##name(const QString &pluginName)const{return loadMetadata(pluginKeys::name, resolvePluginName(pluginName), plugins_metada_cache);} + + METADATA_GETTER(QString, Name) + METADATA_GETTER(QString, Author) + METADATA_GETTER(QString, Description) + METADATA_GETTER(QString, Version) + + METADATA_GETTER(bool, CanBeRoot) + METADATA_GETTER(bool, CanBeChild) + + METADATA_GETTER(int, VID) + METADATA_GETTER(int, PID) + + void scanFolders(); +private: + QHash> plugins_metada_cache; + QHash pluginTable; + + QStringList folderList; +}; + +#endif // PLUGINLOADER_H diff --git a/src/SocExplorerEngine/pluginsInterface/isocexplorerplugin.h b/src/SocExplorerEngine/pluginsInterface/isocexplorerplugin.h new file mode 100644 --- /dev/null +++ b/src/SocExplorerEngine/pluginsInterface/isocexplorerplugin.h @@ -0,0 +1,334 @@ +/*------------------------------------------------------------------------------ +███████╗ ██████╗ ██████╗ ███████╗██╗ ██╗██████╗ ██╗ ██████╗ ██████╗ ███████╗██████╗ +██╔════╝██╔═══██╗██╔════╝ ██╔════╝╚██╗██╔╝██╔══██╗██║ ██╔═══██╗██╔══██╗██╔════╝██╔══██╗ +███████╗██║ ██║██║ █████╗ ╚███╔╝ ██████╔╝██║ ██║ ██║██████╔╝█████╗ ██████╔╝ +╚════██║██║ ██║██║ ██╔══╝ ██╔██╗ ██╔═══╝ ██║ ██║ ██║██╔══██╗██╔══╝ ██╔══██╗ +███████║╚██████╔╝╚██████╗ ███████╗██╔╝ ██╗██║ ███████╗╚██████╔╝██║ ██║███████╗██║ ██║ +╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ + +-- This file is a part of the SOC Explorer Software +-- Copyright (C) 2018, Plasma Physics Laboratory - CNRS +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-------------------------------------------------------------------------------*/ +/*-- Author : Alexis Jeandet +-- Mail : alexis.jeandet@lpp.polytechnique.fr +----------------------------------------------------------------------------*/ +#ifndef ISOCEXPLORERPLUGIN_H +#define ISOCEXPLORERPLUGIN_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ISocexplorerPlugin : public QDockWidget +{ + Q_OBJECT +public: + //! Default plugin constructor, any plugin should call this constructor. + ISocexplorerPlugin(QWidget *parent = Q_NULLPTR,bool createPyObject=true):QDockWidget(parent) + { + Q_UNUSED(createPyObject) + closeAction=Q_NULLPTR; + menu=Q_NULLPTR; + ChildsMenu=Q_NULLPTR; + this->Connected = false; + this->setFeatures(QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetVerticalTitleBar); + } + //! Tells if the plugin is connected, it is used to enable or disable all childrens interfaces. + virtual bool isConnected(){return this->Connected;} + //! Gives the associated Vendor IDentifier, usefull to automatically associate plugins with found + //! hardware while board enumeration. + virtual uint64_t baseAddress(){return this->BaseAddress;} + //! Sets the base address of the current instance, for example if your plugin is supposed to drive + //! an UART it will correspond to the address of it's first register. This address have at least to + //! be set by SocExplorer and it can be user accessible if you want. + virtual void setBaseAddress(uint64_t baseAddress){this->BaseAddress = baseAddress;} + + QList childs; + ISocexplorerPlugin* parent; + QAction* closeAction; + QString instanceName(){return _instanceName;} + QString instance(){return instanceName();} + QMenu* menu; + QMenu* ChildsMenu; + +signals: + //! Signal emited each time the plugin is about to be closed. + void closePlugin(ISocexplorerPlugin* driver); + void activateSig(bool flag); + void registerObject(QObject* object,const QString& instanceName); + +public slots: + virtual int registermenu(QMenu* menu) + { + this->menu = menu->addMenu(this->_instanceName); + this->closeAction = this->menu->addAction(tr("Close plugin")); + QObject::connect(this->closeAction,SIGNAL(triggered()),this,SLOT(closeMe())); + this->ChildsMenu = this->menu->addMenu(QString("Childs")); + for(int i=0;ichilds.count();i++) + { + this->childs.at(i)->registermenu(this->ChildsMenu); + } + emit this->registerObject((QObject*)this,this->instanceName()); + return 0; + } + virtual void postInstantiationTrigger(){} + //! Write slot this is the way your children plugins ask you for writing data. + //! If your plugin is supposed to have childern drivers you should implement this methode. + //! By default this methode forward the write request to the parent plugin. + //! \param Value Pointer the data buffer. + //! \param count Number of 32 bits words you should to write. + //! \param address Address from where you should to start to write. + //! \return Quantity of 32 bits words writtens. + virtual unsigned int Write(unsigned int* Value, int count, uint64_t address) + { + if(parent!=Q_NULLPTR) + { + return parent->Write(Value,count,address); + } + return 0; + } + + void Write(uint64_t address, QList dataList) + { + unsigned int data[dataList.count()]; + for(int i = 0;iRead(Value,count,address); + } + return 0; + } + QVariantList Read(uint64_t address, int count) + { + unsigned int data[count]; + QVariantList result; + Read(data,count,address); + for(int i = 0;i(data[i]))); + } + return result; + } + + virtual void closeMe(){emit this->closePlugin(this);} + + virtual void activate(bool flag) + { + this->setEnabled(flag); + emit this->activateSig(flag); + } + + virtual void setInstanceName(const QString& newName) + { + this->_instanceName = newName; + if(this->menu) + this->menu->setTitle(this->_instanceName); + this->setWindowTitle(newName); + this->setObjectName(newName); + } + + virtual bool dumpMemory(uint64_t address, unsigned int count, QString file) + { + unsigned int* buffer = (unsigned int*)malloc(count*sizeof(unsigned int)); + if(buffer!=NULL) + { + this->Read(buffer,count,address); + QFile outfile(file); + if (!outfile.open(QIODevice::ReadWrite | QIODevice::Text)) + return false; + QTextStream out(&outfile); + for(int i=0;(unsigned int)iRead(buffer,count,address); + if(!format.compare("srec",Qt::CaseInsensitive)) + { + //need to convert from in memory endianness to file endianness + //SREC is always big endian +#if __BYTE_ORDER == __LITTLE_ENDIAN + for(int l=0;l<(count);l++) + { + buffer[l] = socexplorerBswap32(buffer[l]); + } +#elif __BYTE_ORDER == __BIG_ENDIAN + +#endif + codeFragment fragment((char*)buffer,count*4,address); + srecFile::toSrec(QList()<<&fragment,file); + } + if(!format.compare("bin",Qt::CaseInsensitive)) + { + //beware this format is not portable from a big endian host to a litle endian one + codeFragment fragment((char*)buffer,count*4,address); + binaryFile::toBinary(QList()<<&fragment,file); + } + if(!format.compare("hexa",Qt::CaseInsensitive)) + { + QFile outfile(file); + if (!outfile.open(QIODevice::ReadWrite | QIODevice::Text)) + return false; + QTextStream out(&outfile); + for(int i=0;(unsigned int)i(malloc(count*sizeof(unsigned int))); + if(buffer!=Q_NULLPTR) + { + memset(static_cast(buffer),value,count*sizeof(unsigned int)); + this->Write(buffer,count,address); + free(buffer ); + return true; + } + return false; + } + + virtual bool loadbin(uint64_t address,QString file) + { + QFile infile(file); + if (!infile.open(QIODevice::ReadOnly)) + return false; + uint32_t* buffer = (uint32_t*)malloc(infile.size()); + if(buffer!=NULL) + { + infile.read((char*)buffer,infile.size()); + for(int i=0;i<(infile.size()/4);i++) + { + buffer[i] = socexplorerBswap32(buffer[i]); + } + this->Write(buffer,infile.size()/4,address); + free(buffer); + return true; + } + return false; + + } + + virtual bool loadfile(abstractBinFile* file) + { + { + if(file->isopened()) + { + QList fragments= file->getFragments(); + for(int i=0;isize/4; + // TODO fixme, should be the oposite +#if __BYTE_ORDER == __LITTLE_ENDIAN + if(!file->litleendian) + { + uint32_t* buffer = (uint32_t*)malloc(fragments.at(i)->size); + memcpy(buffer,fragments.at(i)->data,fragments.at(i)->size); + if(buffer!=NULL) + { + for(int l=0;l<(size);l++) + { + buffer[l] = socexplorerBswap32(buffer[l]); + } + this->Write(buffer,size,fragments.at(i)->address); + free(buffer); + } + } + else + { + this->Write((uint32_t*) fragments.at(i)->data,size,fragments.at(i)->address); + } +#elif __BYTE_ORDER == __BIG_ENDIAN + if(file->litleendian) + { + uint32_t* buffer = (uint32_t*)malloc(fragments.at(i)->size); + memcpy(buffer,fragments.at(i)->data,fragments.at(i)->size); + if(buffer!=NULL) + { + for(int l=0;l<(size);l++) + { + buffer[l] = socexplorerBswap32(buffer[l]); + } + this->Write(buffer,size,fragments.at(i)->address); + free(buffer); + } + } + else + { + this->Write((uint32_t*) fragments.at(i)->data,size,fragments.at(i)->address); + } +#endif + } + } + return true; + } + } + ISocexplorerPlugin* parentPlugin(){return this->parent;} + ISocexplorerPlugin* toPlugin(){return static_cast(this);} +protected: + QString _instanceName; + uint64_t BaseAddress; + bool Connected; +}; + +Q_DECLARE_INTERFACE(ISocexplorerPlugin, "socexplorer.plugins.ISocexplorerPlugin") + +#endif // ISOCEXPLORERPLUGIN_H diff --git a/src/SocExplorerEngine/pluginsInterface/socexplorerplugininterface.h b/src/SocExplorerEngine/pluginsInterface/socexplorerplugininterface.h --- a/src/SocExplorerEngine/pluginsInterface/socexplorerplugininterface.h +++ b/src/SocExplorerEngine/pluginsInterface/socexplorerplugininterface.h @@ -25,9 +25,8 @@ #include "socexplorerplugininterface_global.h" #include #include +#include -#define ComDriverT 1 -#define PerifDriverT 2 typedef int pluginT; typedef void* (*socexplorerpluginCreateObjectT)();