/*=============================================================================| | PROJECT SNAP7 1.3.0 | |==============================================================================| | Copyright (C) 2013, 2015 Davide Nardella | | All rights reserved. | |==============================================================================| | SNAP7 is free software: you can redistribute it and/or modify | | it under the terms of the Lesser GNU General Public License as published by | | the Free Software Foundation, either version 3 of the License, or | | (at your option) any later version. | | | | It means that you can distribute your commercial software linked with | | SNAP7 without the requirement to distribute the source code of your | | application and without the requirement that your application be itself | | distributed under LGPL. | | | | SNAP7 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 | | Lesser GNU General Public License for more details. | | | | You should have received a copy of the GNU General Public License and a | | copy of Lesser GNU General Public License along with Snap7. | | If not, see http://www.gnu.org/licenses/ | |=============================================================================*/ #ifndef s7_partner_h #define s7_partner_h //--------------------------------------------------------------------------- #include "snap_threads.h" #include "s7_peer.h" //--------------------------------------------------------------------------- using namespace std; //--------------------------------------------------------------------------- #define MaxPartners 256 #define MaxAdapters 256 #define csTimeout 1500 // Connection server destruction timeout const int par_stopped = 0; // stopped const int par_connecting = 1; // running and active connecting const int par_waiting = 2; // running and waiting for a connection const int par_linked = 3; // running and connected const int par_sending = 4; // sending data const int par_receiving = 5; // receiving data const int par_binderror = 6; // error starting passive partner const longword errParMask = 0xFFF00000; const longword errParBase = 0x000FFFFF; const longword errParAddressInUse = 0x00200000; const longword errParNoRoom = 0x00300000; const longword errServerNoRoom = 0x00400000; const longword errParInvalidParams = 0x00500000; const longword errParNotLinked = 0x00600000; const longword errParBusy = 0x00700000; const longword errParFrameTimeout = 0x00800000; const longword errParInvalidPDU = 0x00900000; const longword errParSendTimeout = 0x00A00000; const longword errParRecvTimeout = 0x00B00000; const longword errParSendRefused = 0x00C00000; const longword errParNegotiatingPDU = 0x00D00000; const longword errParSendingBlock = 0x00E00000; const longword errParRecvingBlock = 0x00F00000; const longword errParBindError = 0x01000000; const longword errParDestroying = 0x01100000; const longword errParInvalidParamNumber = 0x01200000; // Invalid param (par_get/set_param) const longword errParCannotChangeParam = 0x01300000; // Cannot change because running const longword errParBufferTooSmall = 0x01400000; // Raised by LabVIEW wrapper class TSnap7Partner; typedef TSnap7Partner *PSnap7Partner; class TConnectionServer; typedef TConnectionServer *PConnectionServer; //------------------------------------------------------------------------------ // CONNECTION SERVERS MANAGER //------------------------------------------------------------------------------ class TServersManager { private: PConnectionServer Servers[MaxAdapters]; TSnapCriticalSection *cs; void Lock(); void Unlock(); int CreateServer(longword BindAddress, PConnectionServer &Server); void AddServer(PConnectionServer Server); public: int ServersCount; TServersManager(); ~TServersManager(); int GetServer(longword BindAddress, PConnectionServer &Server); void RemovePartner(PConnectionServer Server, PSnap7Partner Partner); }; typedef TServersManager *PServersManager; //------------------------------------------------------------------------------ // CONNECTION SERVER (Don't inherit from TcpSrv to avoid dependence) //------------------------------------------------------------------------------ class TConnListenerThread : public TSnapThread { private: TMsgSocket *FListener; TConnectionServer *FServer; public: TConnListenerThread(TMsgSocket *Listener, TConnectionServer *Server) { FServer=Server; FListener=Listener; FreeOnTerminate=false; }; void Execute(); }; typedef TConnListenerThread *PConnListenerThread; class TConnectionServer { private: TSnapCriticalSection *cs; bool FRunning; // Bind Address char FLocalAddress[16]; // Server listener PConnListenerThread ServerThread; // Socket listener PMsgSocket SockListener; // Finds a partner bound to the address PSnap7Partner FindPartner(longword Address); // Locks the Partner list void Lock(); // Unlocks the Partner list void Unlock(); protected: // Workers list PSnap7Partner Partners[MaxPartners]; bool Destroying; void Incoming(socket_t Sock); int Start(); int FirstFree(); public: int PartnersCount; longword LocalBind; TConnectionServer(); ~TConnectionServer(); int StartTo(const char *Address); void Stop(); int RegisterPartner(PSnap7Partner Partner); void RemovePartner(PSnap7Partner Partner); friend class TConnListenerThread; }; typedef TConnectionServer * PConnectionServer; //------------------------------------------------------------------------------ // PARTNER THREAD //------------------------------------------------------------------------------ class TPartnerThread : public TSnapThread { private: TSnap7Partner *FPartner; longword FRecoveryTime; longword FKaElapsed; protected: void Execute(); public: TPartnerThread(TSnap7Partner *Partner, longword RecoveryTime) { FPartner = Partner; FRecoveryTime =RecoveryTime; FreeOnTerminate =false; }; ~TPartnerThread(){}; }; typedef TPartnerThread *PPartnerThread; //------------------------------------------------------------------------------ // S7 PARTNER //------------------------------------------------------------------------------ typedef struct{ bool First; bool Done; uintptr_t Offset; longword TotalLength; longword In_R_ID; longword Elapsed; byte Seq_Out; }TRecvStatus; typedef struct{ bool Done; int Size; int Result; longword R_ID; longword Count; }TRecvLast; extern "C" { typedef void (S7API *pfn_ParBRecvCallBack)(void * usrPtr, int opResult, longword R_ID, void *pdata, int Size); typedef void (S7API *pfn_ParBSendCompletion)(void * usrPtr, int opResult); } class TSnap7Partner : public TSnap7Peer { private: PS7ReqHeader PDUH_in; void *FRecvUsrPtr; void *FSendUsrPtr; PSnapEvent SendEvt; PSnapEvent RecvEvt; PConnectionServer FServer; PPartnerThread FWorkerThread; bool FSendPending; bool FRecvPending; TRecvStatus FRecvStatus; TRecvLast FRecvLast; TPendingBuffer TxBuffer; TPendingBuffer RxBuffer; longword FSendElapsed; bool BindError; byte NextByte; pfn_ParBRecvCallBack OnBRecv; pfn_ParBSendCompletion OnBSend; void ClearRecv(); byte GetNextByte(); void CloseWorker(); bool BlockSend(); bool PickData(); bool BlockRecv(); bool ConnectionConfirm(); protected: bool Stopping; bool Execute(); void Disconnect(); bool ConnectToPeer(); bool PerformFunctionNegotiate(); public: bool Active; bool Running; longword PeerAddress; longword SrcAddress; int BRecvTimeout; int BSendTimeout; longword SendTime; longword RecvTime; longword RecoveryTime; longword KeepAliveTime; longword BytesSent; longword BytesRecv; longword SendErrors; longword RecvErrors; // The partner is linked when the init sequence is terminated //(TCP connection + ISO connection + PDU Length negotiation) bool Linked; TSnap7Partner(bool CreateActive); ~TSnap7Partner(); // Control int Start(); int StartTo(const char *LocAddress, const char *RemAddress, word LocTsap, word RemTsap); int Stop(); int Status(); int GetParam(int ParamNumber, void * pValue); int SetParam(int ParamNumber, void * pValue); // Block send int BSend(longword R_ID, void *pUsrData, int Size); int AsBSend(longword R_ID, void *pUsrData, int Size); bool CheckAsBSendCompletion(int &opResult); int WaitAsBSendCompletion(longword Timeout); int SetSendCallback(pfn_ParBSendCompletion pCompletion, void *usrPtr); // Block recv int BRecv(longword &R_ID, void *pData, int &Size, longword Timeout); bool CheckAsBRecvCompletion(int &opResult, longword &R_ID, void *pData, int &Size); int SetRecvCallback(pfn_ParBRecvCallBack pCompletion, void *usrPtr); friend class TConnectionServer; friend class TPartnerThread; }; #endif // s7_partner_h