/*******************************************************************************/ /* Description: Classe qui implémente le protocole Modbus. Cette classe est héritée par la classe serveur (CModbusCCMgr) ou client (CModbusMaster). Elle sert à interpréter ou formatter des paquets Modbus provenant ou destinés au partenaire. Elle peut être héritée soit un parent qui implémente une instance maître ou client mais pas les deux à la fois. sur le réseau. */ /* ************************************************************************** */ /* Revision: ### YYYMMDD JFM Verision d'origine. ### YYYYMMDD Description du besoin ou du bug Description du changement. */ /* ************************************************************************** */ #ifndef CMODBUSBACKEND_H #define CMODBUSBACKEND_H #include #include #include "ModbusRepository.h" #include #define MODBUS_EXCEPTION_FCT_MASK 0x80 #define MODBUS_RETRY_DELAY 2000 //millisecs #define MODBUS_RETRY_MAX_COUNT 2 //resend an unanswered request this many times #define MODBUS_MAX_NB_REGISTERS 0x7D enum eModbusFunctions { MODBUS_FCT_READ_HOLDING_REGISTERS = 3, MODBUS_WRITE_SINGLE_REGISTER = 6, MODBUS_FCT_WRITE_MULTIPLE_REGISTERS = 16 }; enum eModbusExceptionCodes { MODBUS_EXCEPTION_ILLEGAL_FCT = 1, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS = 2, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE = 3, MODBUS_EXCEPTION_SERVER_DEVICE_FAILURE = 4, MODBUS_EXCEPTION_ACKNOWLEDGE = 5, MODBUS_EXCEPTION_SERVER_DEVICE_BUSY = 6, MODBUS_EXCEPTION_MEMORY_PARITY_ERROR = 8, MODBUS_EXCEPTION_GATEWAY_PATH_UNAVAILABLE = 10, MODBUS_EXCEPTION_GATEWAY_TARGET_DEV_NOT_RESPONDING = 11 }; //Énumération des différents modes possibles enum eModbusModes { MODBUS_MASTER_MODE, MODBUS_SLAVE_MODE, MODBUS_INVALID_MODE }; class CModbusException { public: }; class CModbusPDU { public: qint8 mFunctionCode; //Type de transaction (voir structure eModbusFunctions) pour les fonctions implémentées par le présent module QByteArray mData; //Les données de la transaction }; class CModbusHeader //Objet contenant les données d'un header Modbus (selon la spécification) { public: qint16 mTransactionID; qint16 mProtocolID; qint16 mMessageLength; qint8 mUnitID; }; class CModbusTransaction //Objet contenant les données d'une transaction Modbus { public: CModbusHeader mHeader; //Le header de la transaction CModbusPDU mPDU; //Le PDU (fonction & données) de la transaction (voir classe CModbusPDU) }; class CModbusRequest : public CModbusTransaction //Objet représentant une transaction (mode maître) { public: CModbusRequest(); ~CModbusRequest(); int mRetries; //nombre de fois que la transaction a été retransmise QTimer *mRequestTimer; //Timer servant à retransmettre la requête si aucune réponse ne survient quint16 mStartAddress, mNbRegisters; //For convinience... }; class CModbusBackend : public QObject { Q_OBJECT private: //enum eModbusMasterSMStates //{ // MODBUS_SM_WAIT_FOR__STATE //}; //enum eModbusSlaveSMStates //{ //}; public: CModbusBackend(CModbusRepository *Repo); //Le pointeur vers le registre des données est obligatoire. virtual ~CModbusBackend(); QTcpSocket *mModbusTCPSocketHandle; //Pointeur vers le Socket TCP du réseau Modbus. CModbusRepository *mModbusRepo; //Pointeur vers le registre de données Modbus bool mDataLinkValid; //Flag indiquant si le lien de communication est en santé int mModbusMode; //Indique si le lien modbus de cette instance est exploitée en "slave" (serveur) ou un "master" (client) (voir struct eModbusModes ci-haut). qint8 mDeviceID; //Le device ID Modbus de cette instance. void ModbusLinkDisconnected(); //Fonction appelée par le parent lors d'une perte de la connection. void SetDeviceID(qint8 ID){mDeviceID = ID;} //Master (client) int SendReadHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount); //Fonction servant à transmettre la fonction modbus "Read HR" au partenaire int SendWriteHoldingRegistersRequest(quint16 StartAddress, quint16 RegisterCount); //Fonction servant à transmettre la fonction modbus "Write HR" au partenaire int SendWriteSingleRegisterRequest(quint16 Address); //Fonction servant à transmettre la fonction modbus "Write Single Register" au partenaire virtual void RegistersDatabaseUpdated(quint16 StartAdderss, quint16 Length) = 0; //Fonction virtuelle à être implémentée par la classe dérivée //Appelée lorsque de nouvelles données ont été reçues du réseau Modbus et écrites dans le registre //Master virtual functions virtual void ModbusResponseException(quint8 ExceptionCode, quint8 FctCode); //Fonction virtuelle à être implémentée par la classe dérivée virtual void ModbusWriteMultipleRegsSuccess(); //Fonction virtuelle à être implémentée par la classe dérivée (Modbus Master seulement). Appelée suite à la réception d'une réponse à une requête d'écriture multiple. virtual void ModbusWriteSingleRegsSuccess(); //Fonction virtuelle à être implémentée par la classe dérivée (Modbus Master seulement). Appelée suite à la réception d'une réponse à une requête d'écriture simple. virtual void ModbusRequestMaxRetryReached(); //Fonction virtuelle à être implémentée par la classe dérivée (Modbus Master seulement). Appelée lors de l'atteinte du nombre maximal d'essai de transmission d'une requête. //Sert à informer la classe dérivée lorsqu'une exception se produit dans la communication Modbus (réponse) //Slave virtual function virtual void ModbusRequestException(quint8 ExceptionCode, quint8 FctCode); //Fonction virtuelle à être implémentée par la classe dérivée //Sert à informer le parent lorsqu'une exception se produit dans la communication Modbus (requête) private: //Sur un réseau Modbus, l'eslcave (slave) est un serveur et le maître (master) est un client. //Slave (server) int AnalyzeModbusRequest(CModbusTransaction Transaction); //Exécute l'analyse des données reçues d'une requête Modbus int SendModbusResponse(CModbusTransaction RequestTransaction, QByteArray Data); //Fonction servant à composer et transmettre une réponse à une requête. int SendErrorResponse(CModbusTransaction RequestTransaction, quint8 ErrorCode); //Fonction servant à composer et transmettre une réponse d'erreur à une requête. //Master (client) QList mRequestsList; //Liste des requêtes courantes en attente d'une réponse du serveur int SendModbusRequest(CModbusRequest *Request); //Construit et transmet une nouvelle requête Modbus au partenaire. quint16 GetNewTransactionID(); //Fonction (helper) servant à générer un nouvel ID de transaction nécessaire pour transmettre une nouvelle requête. int AnalyzeModbusResponse(CModbusTransaction Transaction); //Exécute l'analyse des données reçues d'une réponse Modbus quint16 mTransactionIDCounter; //Compteur interne des ID de transactions Modbus int mModbusRequestTimeout; //Valeur du délai d'attente maximal avant de recevoir une réponse à une requête. À l'expiration du timer, la requête est renvoyée. int mModbusMaxRetry; //Valeur du nombre maximal de renvoi d'une requête avant d'invalider la requête. signals: // void RegistersDatabaseUpdated(quint16 StartAdderss, quint16 Length); // //Master signals // void ModbusResponseException(quint8 ExceptionCode, quint8 FctCode); //// //Slave signals // void ModbusRequestException(quint8 ExceptionCode, quint8 FctCode); public slots: void ModbusDataReady(); //Slot indiquant au module que des données sont arrivées et sont attente dans le Socket. void RequestTimerExpired(); //Slot indiquant qu'un timer de requête a expiré. }; QDataStream &operator<<(QDataStream &out, const CModbusHeader &source); QDataStream &operator>>(QDataStream &in, CModbusHeader &dest); #endif // CMODBUSBACKEND_H