00001 /*************************************************************************** 00002 LOW_netSegment.h - description 00003 ------------------- 00004 begin : Sun Jul 7 2002 00005 copyright : (C) 2002 by Harald Roelle 00006 email : roelle@informatik.uni-muenchen.de 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #ifndef LOW_NETSEGMENT_H 00019 #define LOW_NETSEGMENT_H 00020 00021 00022 #include <algorithm> 00023 00024 #include "LOW_types.h" 00025 #include "LOW_objectIDFactory.h" 00026 #include "LOW_device.h" 00027 #include "LOW_link.h" 00028 #include "LOW_objectSynchronizer.h" 00029 00030 00031 class LOW_device; // Forward declaration to avoid loops. 00032 00033 00034 /** Single segment of the 1-Wire net. 00035 00036 The class models a single segment reachable by a concrete link 00037 of the 1-Wire network. 00038 00039 Objects for devices are automatically instanciated via LOW_deviceFactory. 00040 The objects are cached in two maps: 00041 00042 - aliveDevMap: Contains currently present devices on the segment. 00043 00044 - graveyardMap: Contains formerly present devices on the segment. 00045 00046 This means, that once a device is not visible any more, the device object 00047 is not deleted but burried on the graveyard. Once the device is visible again, 00048 it is revitalized. 00049 00050 This class is thread-safe. 00051 00052 @author Harald Roelle 00053 @author Parts of the documentation by Dallas Semiconductors / Maxim Integrated Products 00054 */ 00055 class LOW_netSegment : public LOW_objectSynchronizer 00056 { 00057 00058 //======================================================================================= 00059 public: 00060 00061 //===================================================================================== 00062 // 00063 // exceptions 00064 // 00065 00066 /** Exception base class for all exceptions thrown by LOW_netSegment. */ 00067 class_DERIVE_FROM_EXCEPTION( netSegment_error, LOW_exception); 00068 00069 /** Exception to indicate that one or more expeced devices were not found. */ 00070 class_DERIVE_FROM_EXCEPTION( noDevice_error, netSegment_error); 00071 00072 00073 //===================================================================================== 00074 // 00075 // type definitions 00076 // 00077 00078 typedef LOW_objectIDFactory::objectID_t segmentID_t; /**< segment ID type */ 00079 00080 typedef std::vector<LOW_netSegment*> netSegPtrVec_t; /**< Vector type of class pointers. */ 00081 00082 00083 //===================================================================================== 00084 // 00085 // methods 00086 // 00087 00088 /** Get the LOW_link instance associated with this segment. 00089 @return Reference to the link instance. 00090 */ 00091 virtual LOW_link& getLink(); 00092 00093 00094 /** Get wether there is an external power line on the segment. 00095 @returns Wether there is an external power line on the segment. 00096 */ 00097 virtual bool getHasExternalPower() const; 00098 00099 00100 /** Get a specific device. 00101 00102 Devices are searched in the internal device list only. No bus actions are performed. 00103 00104 <B>Note:</B>:The device type to look for is selected by the template parameter. 00105 00106 @param inDevID ID of the device to get. 00107 @return Requested device. 00108 @throw LOW_device::familyMismatch_error Thrown when family code of selected class 00109 and the one in the ID don't match. 00110 @throw noDevice_error Thrown when requested device is not present. 00111 */ 00112 template<class devType> devType* getDevice( const LOW_deviceID inDevID); 00113 00114 00115 /** Get devices of a specific type. 00116 00117 Devices are searched in the internal device list only. No bus actions are performed. 00118 Selecting any device type will result in the complete list of devices 00119 known to be present on the segment. 00120 00121 <B>Note:</B>: The device type to look for is selected by the template parameter. 00122 To select any device type use LOW_device. 00123 00124 @return Vector of found devices. 00125 */ 00126 template<class devType> std::vector<devType*> getDevices() const; 00127 00128 00129 /** Search for devices on the segment. 00130 00131 Selecting any device type will result in searching the whole segment. 00132 00133 <B>Note:</B>: The device type to look for is selected by the template parameter. 00134 To select any device type use LOW_device. 00135 00136 <B>Note:</B>: The bus will be actively searched. Newly found devices will be 00137 added to the internal device list. 00138 00139 @param inOnlyAlarm Determines whether to look only for alarming devices of the 00140 requested type. 00141 @return Vector of found devices. 00142 */ 00143 template<class devType> std::vector<devType*> searchDevices( const bool inOnlyAlarm = false); 00144 00145 00146 /** Verify existance of a specific device on the segment. 00147 00148 <B>Note:</B>: In case you already own a reference to the device, use the 00149 corresponding method from LOW_device. 00150 00151 <B>Note:</B>: The bus will be actively searched. Newly found devices will be 00152 added to the internal device list. 00153 00154 @param inDevID ID of the device to verify. 00155 @param inOnlyAlarm Determines whether to report existance only when 00156 the device is alarming. 00157 @param inDoReset Whether to reset the bus afterwards. 00158 @return Boolean indicates wheter the device could be found or not. 00159 */ 00160 virtual bool verifyDevice( const LOW_deviceID inDevID, const bool inOnlyAlarm = false, 00161 const bool inDoReset = true); 00162 00163 00164 00165 //======================================================================================= 00166 protected: 00167 00168 //===================================================================================== 00169 // 00170 // friends 00171 // 00172 00173 friend class LOW_network; /**< Enable access to static pseudo constructor and destructor */ 00174 friend class LOW_device; /**< Enable access to unregister a device on destruction. */ 00175 00176 00177 00178 //===================================================================================== 00179 // 00180 // static attributes 00181 // 00182 00183 __LOW_SYNCHRONIZE_DEFINE_PROTECTED_LOCK__ 00184 00185 00186 00187 //===================================================================================== 00188 // 00189 // constructors 00190 // 00191 00192 /** Destructor. 00193 Destroys all objects of devices (in both maps). 00194 */ 00195 virtual ~LOW_netSegment(); 00196 00197 00198 00199 //===================================================================================== 00200 // 00201 // static methods 00202 // 00203 00204 /** Discovers network segments on a link. 00205 @warning By now only a single segment is supported. 00206 00207 @param inLink The link to be searched for network segments. 00208 */ 00209 static netSegPtrVec_t newSegmentsFromLink( LOW_link &inLink); 00210 00211 00212 00213 //===================================================================================== 00214 // 00215 // methods 00216 // 00217 00218 /** Indicate that a device instance is going to be deleted. 00219 Function mainly used by the destructor of LOW_device. 00220 00221 @param inDev Device to unregister. 00222 */ 00223 virtual void unregisterDevice( const LOW_device *inDev); 00224 00225 00226 00227 //===================================================================================== 00228 // 00229 // protected addressing/searching methods 00230 // 00231 00232 /** Select a single device on a link. 00233 00234 The matchROM command followed by a 64-bit ROM code sequence 00235 allows the bus master to address a specific slave device on a 00236 multidrop or single-drop bus. Only the slave that exactly matches 00237 the 64-bit ROM code sequence will respond to the function command 00238 issued by the master; all other slaves on the bus will wait for a 00239 reset pulse. 00240 00241 @param inDevice Device to select. 00242 @throw noDevice_error Thrown when no device was found on the bus. 00243 */ 00244 virtual void cmd_MatchROM( const LOW_device *inDevice) const; 00245 00246 00247 /** Select all devices on a link. 00248 00249 The master can use this command to address all devices on the bus 00250 simultaneously without sending out any ROM code information. 00251 For example, the master can make all DS18S20s on the bus perform 00252 simultaneous temperature conversions by issuing a Skip ROM command 00253 followed by a ConvertT command. 00254 00255 @throw noDevice_error Thrown when no device was found on the bus. 00256 */ 00257 virtual void cmd_SkipROM() const; 00258 00259 00260 /** Read ID number from bus. 00261 00262 The read ROM command allows the bus master to read the slave's 64-bit ROM 00263 code without using the Search ROM procedure. 00264 00265 <B>Note</B>: The read ROM command can only be used when there is one slave on 00266 the bus. If this command is used when there is more than one slave 00267 present on the bus, a data collision will occur when all the slaves 00268 attempt to respond at the same time. 00269 00270 @return ID of the found device. 00271 @throw noDevice_error Thrown when no device was found on the bus. 00272 */ 00273 virtual LOW_deviceID cmd_ReadROM() const; 00274 00275 00276 /** Scan the bus for devices. 00277 00278 The searchROM command allows the master to determine the number of slaves 00279 and their device types. The master learns the ROM codes through a process of 00280 elimination that requires the master to perform a Search ROM cycle (i.e., 00281 Search ROM command followed by data exchange) as many times as necessary to 00282 identify all of the slave devices. 00283 00284 If there is only one slave on the bus, the simpler Read ROM command can be used 00285 in place of the Search ROM process. 00286 00287 The search can be narrowed to devices which their alarm flag set and/or to 00288 specific family codes. 00289 00290 @param inOnlyAlarm Whether to look only for alarming devices. 00291 @param inFamCode Specific family code for narrowing search. 00292 @return List of found IDs. 00293 @throw noDevice_error Thrown when no device was found on the bus. 00294 */ 00295 virtual LOW_deviceID::deviceIDVec_t cmd_SearchROM( const bool inOnlyAlarm = false, 00296 const LOW_deviceIDRaw::devFamCode_t inFamCode = LOW_device::anyDev_famCode) const; 00297 00298 00299 /** Scan the bus for a specific device. 00300 00301 @param inDevID Device to search for. 00302 @param inOnlyAlarm Whether to report as found only when alarming. 00303 @param inDoReset Whether to reset the bus afterwards. 00304 @return Indicated whether the device was found or not. 00305 @throw noDevice_error Thrown when no device was found on the bus. 00306 */ 00307 virtual bool cmd_SearchROMVerify( const LOW_deviceID inDevID, const bool inOnlyAlarm = false, 00308 const bool inDoReset = true) const; 00309 00310 00311 00312 //======================================================================================= 00313 private: 00314 00315 //===================================================================================== 00316 // 00317 // attributes 00318 // 00319 00320 const segmentID_t segmentID; /**< Identifier of the segment. */ 00321 LOW_link &link; /**< Link this segment is present on */ 00322 bool hasExternalPower; /**< Whether there is an additional line for external power supply available */ 00323 LOW_device::deviceMap_t aliveDevMap; /**< Map of currently present devices on the segment */ 00324 LOW_device::deviceMap_t graveyardMap; /**< Map of formerly present devices on the segment */ 00325 00326 00327 //===================================================================================== 00328 // 00329 // constructors 00330 // 00331 00332 /** Constructor from link. 00333 Triggers initial search of devices on the segment. 00334 @param inLink The link the segment resides on. 00335 */ 00336 LOW_netSegment( LOW_link &inLink); 00337 00338 00339 //===================================================================================== 00340 // 00341 // operator overloading 00342 // 00343 00344 virtual bool operator==(LOW_netSegment &inSegment) const; /**< Comparison based on segmentID. */ 00345 00346 00347 //===================================================================================== 00348 // 00349 // methods 00350 // 00351 00352 /** Safely cast a generic device pointer to a specific one. 00353 The type to cast to is specified by the template parameter. 00354 00355 @param inPtr Generic pointer to be casted. 00356 @return Casted pointer of the requested type. 00357 @throw LOW_device::illegalCast_error Thrown when type cast is not possible. 00358 */ 00359 template<class castType> inline castType* devicePtr_cast( LOW_device *inPtr) const; 00360 00361 00362 /** Move a device from the alive map to the graveyard. 00363 If not in alive map, the method returns silently. 00364 00365 @param inDev The device to move. 00366 */ 00367 virtual void buryDevice( const LOW_device *inDev); 00368 00369 00370 /** Move a device from the graveyard to the alive map. 00371 If not on graveyard, the method returns silently. 00372 00373 @param inDev The device to move. 00374 */ 00375 virtual void revitalizeDevice( const LOW_device *inDev); 00376 00377 00378 /** Add a device to the alive map. 00379 00380 When the device is already in the alive map nothing is done. 00381 When it is on the graveyard, it is moved to the alive map. 00382 When it does not exist at all, a new instance is created. 00383 00384 @param inDevID The ID of the device to add. 00385 @return The added device. 00386 */ 00387 virtual LOW_device* addDevice( const LOW_deviceID inDevID); 00388 00389 00390 /** Removes a device from either the alive map or the graveyard. 00391 If it does not exist, the method returns silently. 00392 00393 @param inDev The device to remove. 00394 */ 00395 virtual void removeDevice( const LOW_device *inDev); 00396 00397 }; 00398 00399 00400 00401 //===================================================================================== 00402 // DEFINITIONS COMPILERS CANNOT HANDLE TO GO DIRECTLY INTO THE LIBRARY 00403 //===================================================================================== 00404 00405 00406 //===================================================================================== 00407 // 00408 // template definitions 00409 // 00410 00411 template<class devType> devType* LOW_netSegment::getDevice( const LOW_deviceID inDevID) 00412 { 00413 __LOW_SYNCHRONIZE_METHOD_READ__ 00414 00415 if ( devType::familyCode != LOW_device::anyDev_famCode 00416 && devType::familyCode != LOW_device::unknownDev_famCode 00417 && devType::familyCode != inDevID.getFamilyCode() ) 00418 throw LOW_device::familyMismatch_error( "Requested type does not match given device ID", __FILE__, __LINE__); 00419 00420 // look in the map of alive devices 00421 LOW_device::deviceMap_t::iterator found = aliveDevMap.find( inDevID); 00422 if ( found == aliveDevMap.end() ) 00423 throw noDevice_error( "Device not present on segment", __FILE__, __LINE__); 00424 00425 return devicePtr_cast<devType>(found->second); 00426 } 00427 00428 00429 template<class devType> std::vector<devType*> LOW_netSegment::getDevices() const 00430 { 00431 __LOW_SYNCHRONIZE_METHOD_READ_WEAK__ 00432 00433 std::vector<devType*> retVal; 00434 00435 // look in the map of alive devices 00436 for( LOW_device::deviceMap_t::const_iterator a=aliveDevMap.begin(); a!=aliveDevMap.end(); ++a) { 00437 if ( devType::familyCode == LOW_device::anyDev_famCode 00438 || ( devType::familyCode==LOW_device::unknownDev_famCode && dynamic_cast<devType*>(a->second)!=0 ) 00439 || devType::familyCode == a->second->getID().getFamilyCode()) 00440 retVal.push_back( devicePtr_cast<devType>(a->second)); 00441 } 00442 00443 return retVal; 00444 } 00445 00446 00447 template<class devType> std::vector<devType*> LOW_netSegment::searchDevices( const bool inOnlyAlarm) 00448 { 00449 __LOW_SYNCHRONIZE_METHOD_WRITE_WEAK__ 00450 00451 LOW_deviceID::deviceIDVec_t idList = cmd_SearchROM( inOnlyAlarm, devType::familyCode); 00452 std::vector<devType*> retVal = std::vector<devType*>( idList.size()); 00453 00454 // in case of NOT alarm search, remember the active devices 00455 LOW_device::devPtrVec_t formerlyActiveDevs; 00456 if ( !inOnlyAlarm ) { 00457 std::vector<devType*> tmpVec = getDevices<devType>(); 00458 for( unsigned int a=0; a<tmpVec.size(); a++) 00459 formerlyActiveDevs.push_back( tmpVec[a]); 00460 } 00461 00462 for( unsigned int a=0; a<idList.size(); a++) { 00463 LOW_device *newDev = addDevice( idList[a]); 00464 retVal[a] = devicePtr_cast<devType>(newDev); 00465 00466 // in case it was already present, remove the device from the formerly active devices 00467 if ( !inOnlyAlarm ) { 00468 LOW_device::devPtrVec_t::iterator foundFormerlyAlive = find( formerlyActiveDevs.begin(), formerlyActiveDevs.end(), newDev); 00469 if ( foundFormerlyAlive!=formerlyActiveDevs.end()) 00470 formerlyActiveDevs.erase( foundFormerlyAlive); 00471 } 00472 } 00473 00474 // what is now remaining is not present any more and therefore is sent to the graveyard 00475 if ( !inOnlyAlarm ) { 00476 for( unsigned int a=0; a<formerlyActiveDevs.size(); a++) 00477 buryDevice( formerlyActiveDevs[a]); 00478 } 00479 00480 return retVal; 00481 } 00482 00483 00484 template<class castType> inline castType* LOW_netSegment::devicePtr_cast( LOW_device *inPtr) const 00485 { 00486 // no locking necessary 00487 00488 castType* retVal = dynamic_cast<castType*>(inPtr); 00489 00490 if ( retVal == 0 ) 00491 throw LOW_device::illegalCast_error( "Unexpected illegal type cast", __FILE__, __LINE__); 00492 00493 return retVal; 00494 } 00495 00496 00497 #endif 00498