/* Copyright (c) 20011 Hovanes Egiyan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //!================================================================================================= //! //! Here we call a device a single CAN bus connection on an AnaGate Quattro module. //! Each connection is represented by an object. It is also assigned a connection number. //! Also we introduce a claas to describe the basic parameters of the connection: //! IP number and bus number on the AnaGate device. The bus number corresponds to //! 'A', 'B', 'C', 'D' connectors on the AnaGate quattro device, 0, 1, 3, 4, respectively. //! //! The object of BaseIUDevice class should be created whenever a CANbus needs to be connected to control //! the Indiana University bases. DeviceID type define within BaseIUDevice is used to describe //! the properties of this device by a single object. Each object of BaseIUDevice will have a member //! of this type, and it will also have an integer member, "handle", which is used by the AnaGateCAN //! driver for AnaGate Quattro device. This class also has a mutex member for locking within the //! instances of this class, and another global mutex to lock for all obejcts of this class. //! The code is written in such a way that there is no possibility of locking both global and //! instance mutex at the same time to avoid strange race conditions. //! //! In addition, there is also a static map of all devices to keep track of them. The existence //! of a device is checked using DeviceExists() method. If the constructor is called for a device //! that already exists in the map, an exception is thrown, and the new device is not added to the //! static map of all devices, and the connection is not initialized. //! //! The main functionality of this class is send the messages and retrieve message from a //! CANbus that this device connection represents. Send method sends the buffer to the device //! using AnaGateCAN driver, and immediately returns if there are no error. In case of an //! error condition an exception is thrown based on the AnaGateCAN error code description. //! //!================================================================================================= #ifndef _BaseIUDevice_HH_ #define _BaseIUDevice_HH_ extern "C" { #include #include #include }; #include #include #include #include #include #include #include #include #include //#include "AnaGateDllCan.h" #include "AnaGateDLL.h" #include "AnaGate.h" using namespace std; #include "MtxLock.hh" #include "BaseIUException.hh" #include "BaseIUMessage.hh" #include "BaseIUCommand.hh" #include "BaseIUBuffer.hh" class BaseIUDevice { public: //! class for exceptions at OPEN failures class FailedOpenDevice : public BaseIUException { public: FailedOpenDevice( const int code ) : BaseIUException( code ){;} FailedOpenDevice( const string str ) : BaseIUException( str ) {;} }; //! class for exceptions at CONFIG failures class FailedConfigDevice : public BaseIUException { public: FailedConfigDevice( const int code ) : BaseIUException( code ){;} FailedConfigDevice( const string str ) : BaseIUException( str ) {;} }; //! class for exceptions at CLOSE failures class FailedCloseDevice : public BaseIUException { public: FailedCloseDevice( const int code ) : BaseIUException( code ){;} FailedCloseDevice( const string str ) : BaseIUException( str ) {;} }; //! class for exceptions at WRITE failures class FailedWriteDevice : public BaseIUException { public: FailedWriteDevice( const int code ) : BaseIUException( code ){;} FailedWriteDevice( const string str ) : BaseIUException( str ) {;} }; //! class for exceptions at READ failures class FailedReadDevice : public BaseIUException { public: FailedReadDevice( const int code ) : BaseIUException( code ){;} FailedReadDevice( const string str ) : BaseIUException( str ) {;} }; //! A class for identifying a bus based on the IP address string and //! the number (ASCII character code) of the bus on the AnaGate device class DeviceID { protected: //! These two members are the ones really identifying the connection string diIP ; //! IP address int diBus; //! Bus number on the Anagate module, 0 - 4. value 4- means all busses ("E"). //! The connection port name below does not identify the device, i.e. //! it is not used in the comparisons. It is an attribute that //! is kept in this class to avoid creating a derived class just for that. //! This name might have been better defined for virtual bus id class instead of device id string diPort; //! Connection port name public: //! Default constructor is also defined DeviceID() : diIP("127.0.0.1"), diBus(0), diPort("") {;} //! This is the main constructor DeviceID( string ip, string bus, string portName ) : diIP(ip), diBus(String2Int(bus)), diPort(portName) {;} DeviceID( string ip, int bus, string portName ) : diIP(ip), diBus(bus), diPort(portName) {;} //! Copy constructor DeviceID( const DeviceID& id ) { *this = operator=( id ) ; } //! Assignment operator DeviceID& operator=( const DeviceID& id ) { diIP = id.diIP; diBus = id.diBus; diPort = id.diPort; return *this; } //! Add port after the busID. Useful when adding port to an ID indicating //! an anagate device, not a particular port DeviceID& operator+( const unsigned busNumber ) { diBus = busNumber; diPort = diPort + ":" + Int2String( diBus ); return *this; } DeviceID& operator+( const string busName ) { return this->operator+( String2Int( busName ) ); } //! Define comparison operator since we will have maps of this class //! We do not compare the connection names though inline bool operator==( const DeviceID& id ) const { if( diIP == id.diIP && diBus == id.diBus ) return true; else return false; } //! less operator, find operator for map class happens to use this for cmparison inline bool operator<(const DeviceID& id) const { if (diIP < id.diIP) return true; if (diIP > id.diIP) return false; if (diBus < id.diBus) return true; return false; } //! greater operator inline bool operator>( const DeviceID& id ) const { if ( diIP > id.diIP ) return true; if ( diIP < id.diIP ) return false; if ( diBus > id.diBus ) return true; return false; } //! A method to convert the bus port number (A, B, C, D, E) on the AnaGate device //! to integer numbers 0, 1, 2, 3, 4. The body is in the implementation file. static int String2Int( const string bus ); static string Int2String( const int bus ); inline string GetIP() { return diIP ; } //! Return IP number inline int GetBus() { return diBus; } //! Return bus number inline string GetPort() { return diPort; } //! Return connection port name inline string GetBusStr() { return Int2String( diBus ); } //! Return bus name inline string SetIP( string ip ) { return (diIP = ip);} //! Set IP number inline int SetBus( int bus ) { return (diBus = bus); } //! Set bus number inline string SetPort( string port ) { return ( diPort = port ); } //! Set number }; protected: DeviceID bdID; //! Device ID (Bus #, the module IP and the connection n number) AnaInt32 bdHandle; //! Device Handle used in AnaGateCAN driver //! Mutex for an object pthread_mutex_t bdMutex; //! Mutex attributes for an object pthread_mutexattr_t bdMtxAttr; //! Initialize the mutex for the object void InitMutex(); //! Destroy the mutex for the object void CloseMutex(); void InitConnection(); //! Method to initialize the CAN bus connection void CloseConnection(); //! Close connection to the CAN bus connection BaseIUDevice* DeviceExists(); //! Find the port name of the existing connection if there is one BaseIUDevice& operator=( const BaseIUDevice& port ); //! Not allowed BaseIUDevice( const BaseIUDevice& port ); //! Not allowed public: static unsigned bdDebFlag; //! Debug flag static int bdFormatFlag; //! Format flag for can ID static long bdConnectTimeOut; //! Time to timeout on connect static int bdRate; //! Bit rate for CAN bus static unsigned char bdOperMode; //! Bus Operating mode static bool bdTermination; //! Integrated CAN bus termination static bool bdHighSped; //! High Speed mode usage flag static bool bdDataConfirm; //! Confirm all data requests static bool bdMonitor; //! Not Discard all telegrams static bool bdTimeStamp; //! Timestamp flag static const int bdSuccess; //! Success return constant static const int bdError; //! Error return constant static pthread_mutex_t bdGlobMutex; //! Global mutex static pthread_mutexattr_t bdGlobMtxAttr; //! Global mutex attributes static int bdDummyInt; //! Dummy integer static const long bdWriteReadDelay; //! Delay between writing //! and reading the FIFO (us) //! Hash table to keep track of all devices. The key is this map is the handle from AnaGateCAN //! library. The value is the ID of the device with that device handle. static map bdDeviceMap; //! Hash table to keep track of all handles. The key in this hash is the device ID, //! which is determined by the IP number and the CAN bus port number on the AnaGate //! bridge device. Note that the connection number, although is a part of DeviceID //! structure, it is not a part of comparison of two IDs. static map bdPtrMap; //! Map of maps for FIFO for each device for each command. The first key in this map //! is the connection number. Then the second key is the address of the board on the //! CANbus attached to the connection number defined by the first key. The value corresponding //! to the second key is a "deque" (FIFO) whose elements are strings. The BaseIUMessage-s are the //! bytes that are read by the CallBack methods and placed in this FIFO. static BaseIUBuffer bdFIFO; //! Constructor for a connection for device identified with DeviceID class BaseIUDevice( DeviceID& devID ) ; //! Destructor virtual ~BaseIUDevice(); //! Reset CAN bus connection void Reset(); //! Send command to a board with a specific address on a //! AnaGateCAN connection specified by dev pointer BaseIUMessage Send( long addr, BaseIUMessage& cmdMsg ); //! Returns a vector of addresses which have response //! in the FIFO vector GetAddressVector(); //! Return the part of the FIFO for the boards and clear //! entries for that board from the main FIFO if clearFlag is true. deque GetDeque( int addr, bool clearFlag = true ); //! Write to the digital output of the device unsigned long WriteDigital( unsigned long outputWord ) ; //! Read digital input pins unsigned long ReadDigitalInputs(); //! Read digital output pins unsigned long ReadDigitalOutputs(); // Clear all address for this device virtual void ClearFIFO(); //! Initialize global mutex static int InitGlobalMutex(); //! Callback function for the bus readback static void WINAPI CallBack( AnaUInt32 canAddr, const char* inBuffer, AnaInt32 bufLength, AnaInt32 nFlags, AnaInt32 handle ); inline DeviceID GetID() //! Get bus connection ID (IP, bus, number) { MtxLock objLock( bdMutex ); return bdID ; } inline int GetHandle() //! Get the handle used by AnaGate driver { MtxLock objLock( bdMutex ); return bdHandle ; } inline BaseIUBuffer& GetFIFO() const { return bdFIFO; } inline string GetPortName() //! Get CAN bus port name used by this object { MtxLock objLock( bdMutex ); return bdID.GetPort(); } inline string GetIP() //! Get the IP address of the AnaGate device { MtxLock objLock( bdMutex ); return bdID.GetIP(); } inline int GetBus() //! Get the bus number on the AnaGate device { MtxLock objLock( bdMutex ); return bdID.GetBus(); } inline string GetBusStr() //! Get the bus name on the AnaGate device { MtxLock objLock( bdMutex ); return bdID.GetBusStr(); } inline int Sleep( unsigned long time = bdWriteReadDelay ) { MtxLock objLock( bdMutex ); return usleep( time ); } }; #endif // _BaseIUDevice_HH_