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