00001 /* 00002 * This file contains simple working unit from that may be simply derived others units. 00003 * 00004 * Author: 00005 * Tomas Mrkvicka 00006 * xmrkvi03@stud.fit.vutbr.cz 00007 * 00008 */ 00009 00010 #include <cassert> 00011 00012 #include "pipeline/SimpleUnit.h" 00013 00014 //////////////////////////////////////////////////////////////////////////////// 00015 //////////////////////////////////////////////////////////////////////////////// 00016 //////////////////////////////////////////////////////////////////////////////// 00017 // TSimpleUnit 00018 00019 /** Tato staticka metoda tvori telo vlakna ve kterem jednotka 00020 * zpracovava snimky 00021 * 00022 * \param ptr [in] ukazatel na jednotku typu TSimpleUnit 00023 */ 00024 DWORD WINAPI TSimpleUnit::TSimpleUnitThread(void* ptr) 00025 { 00026 TSimpleUnit * simple_unit = (TSimpleUnit*)ptr; 00027 00028 /** Smycka bezi dokud vlakno nezastavi. 00029 */ 00030 while( simple_unit->GetState() != ENUM_UNIT_STOP ) 00031 { 00032 simple_unit->Loop(); 00033 }; 00034 00035 return 0; 00036 } 00037 //OK 2007-08-25 18:42:47 B04-315B\Tom 00038 00039 /** Konstruktor. 00040 * Vytvori jednotku, ktera musi byt nasledne spustena pomoci metody Start. 00041 * 00042 * \param dispatcher [in] rozhrani na objekt pro ziskavani novych snimku z kamery 00043 * \param unit [in] rozhrani vlastni zpracovavajici jednotky - objekt je jednotkou automaticky 00044 * znicen v destruktoru 00045 * \param lockFrame [in] tento parametr urcuje zda bude jednotka zamykat snimky 00046 * Zamknutim snimku jednotka neumozni zobrazit snimek dokud neni kompletne zpracovan. 00047 */ 00048 TSimpleUnit::TSimpleUnit( 00049 TDispatcherInterface* dispatcher, 00050 TSimpleUnitProcessingInterface * unit, 00051 BOOL lockFrame) 00052 { 00053 m_thread = NULL; 00054 00055 m_state = ENUM_UNIT_LOADFRAME; 00056 00057 m_dispatcher = dispatcher; 00058 m_unit = unit; 00059 00060 m_lockFrame = lockFrame; 00061 m_frame = NULL; 00062 00063 m_interval = 0; 00064 } 00065 //OK 2007-08-25 18:42:50 B04-315B\Tom 00066 00067 /** Destruktor 00068 * 00069 * Destruktor smi byt volan pouze po radnem zastaveni jednotky metodou Stop!!! 00070 * To zajisti, ze jednotka nebude udrzovat reference na zadne snimky. 00071 */ 00072 TSimpleUnit::~TSimpleUnit(void) 00073 { 00074 //snimek musi byt odstranen pred znicenim - toho je docileno zastavenim jednotky 00075 assert( m_frame == NULL ); 00076 00077 delete m_unit; 00078 m_unit = NULL; 00079 } 00080 //OK 2007-08-25 18:42:52 B04-315B\Tom 00081 00082 /** Zniceni objektu. 00083 * 00084 * Neni zde zadne pocitani referenci, takze jednotka se znici okamzite. 00085 * 00086 * Metoda smi byt volana v okamziku kdy jiz jednotka nebezi. 00087 * 00088 * Tato metoda musi byt reimplementovana v odvozene tride !!! 00089 */ 00090 void TSimpleUnit::Release(void) 00091 { 00092 delete this; 00093 } 00094 //OK 2007-08-25 18:42:54 B04-315B\Tom 00095 00096 /** Spusteni jednotky. 00097 * 00098 * Vraci TRUE pokud byla jednotka spustena nebo jiz bezi. 00099 * 00100 * FALSE vraci pri kriticke chybe, kdyz napr. neni mozne vytvorit vlakno apod. 00101 * V takovem pripade je nutne okmazite ukoncit aplikaci. 00102 */ 00103 BOOL TSimpleUnit::Start(void) 00104 { 00105 if( ! m_thread ) 00106 { 00107 //jednotka nebezi 00108 00109 //nastavime jednotce pocatecni stav 00110 SetState(ENUM_UNIT_LOADFRAME); 00111 00112 //spustime vypocetni vlakno 00113 m_thread = new TThread; 00114 BOOL res = m_thread->Run( (FUNC_PTR)TSimpleUnitThread,(void*)this); 00115 00116 if ( res ) 00117 { 00118 return TRUE; 00119 } 00120 else 00121 { 00122 //nejaka chyba 00123 delete m_thread; 00124 m_thread = NULL; 00125 return FALSE; 00126 } 00127 } 00128 else 00129 { 00130 //jednotka uz bezi 00131 return TRUE; 00132 } 00133 } 00134 //OK 2007-08-25 18:43:10 B04-315B\Tom 00135 00136 /** Zastaveni jednotky. 00137 * 00138 * Vraci TRUE pokud se jednotku podarilo zastavit. 00139 */ 00140 BOOL TSimpleUnit::Stop(void) 00141 { 00142 if( m_thread ) 00143 { 00144 //jednotka byla spustena 00145 00146 if( m_thread->IsTerminated() ) 00147 { 00148 //vlakno uz bylo ukonceno - pouze uklidime 00149 m_thread->Finish(); //zde metoda uspeje 00150 delete m_thread; 00151 m_thread = NULL; 00152 } 00153 else 00154 { 00155 //vlakno stale bezi - pokusime se ho ukoncit standardni cestou 00156 //zajistime ze vlakno jednotky nezmeni stav 00157 m_critical.Enter(); 00158 if(m_state == ENUM_UNIT_STOP) 00159 { 00160 //jednotka jiz stoji, bude brzy ukoncena v ramci sveho vlakna 00161 } 00162 else 00163 { 00164 switch(m_state) 00165 { 00166 //jednotka pracuje - dame ji pokyn ze po dokonceni uz nema pokracovat 00167 case ENUM_UNIT_WORK: 00168 case ENUM_UNIT_LOADFRAME: 00169 m_state = ENUM_UNIT_FINISHWORK; 00170 break; 00171 00172 //jednotka dokoncuje ulohu 00173 case ENUM_UNIT_FINISHWORK: 00174 //jednotka se brzy sama zastavi 00175 break; 00176 00177 default: 00178 //nejaka chyba 00179 m_state = ENUM_UNIT_FINISHWORK; 00180 assert(false); 00181 break; 00182 } 00183 } 00184 m_critical.Leave(); 00185 00186 //nyni cekame na ukonceni jednotky 00187 //todo - tady muze pri zavazne chybe vzniknout nekonecny cyklus - zatim nevyresene 00188 while( ! m_thread->IsTerminated() ) 00189 { 00190 Sleep(20); 00191 }; 00192 00193 //nyni jednotka stoji - ukoncime ji 00194 m_thread->Finish(); //metoda uspeje 00195 delete m_thread; 00196 m_thread = NULL; 00197 } 00198 00199 //odstranime zbyvajici snimek - pokud existuje 00200 if( m_frame ) 00201 { 00202 m_frame->Release(); 00203 00204 //odstranime zamek - pokud jednotka zamyka snimky 00205 if(m_lockFrame) 00206 { 00207 m_frame->ReleaseLock(); 00208 } 00209 m_frame = NULL; 00210 } 00211 00212 return TRUE; 00213 } 00214 else 00215 { 00216 //jednotka neni spustena 00217 return TRUE; 00218 } 00219 } 00220 //OK 2007-08-25 18:43:29 B04-315B\Tom 00221 00222 /** Hlavni smycka jednotky. 00223 * 00224 * Je volana ze staticke metody TSimpleUnit::Run() a obsahuje ridici logiku cele jednotky. 00225 */ 00226 void TSimpleUnit::Loop(void) 00227 { 00228 //pouzijime kopii aktualniho stavu - kvuli synchronizaci vlaken 00229 m_critical.Enter(); 00230 EnumUnitState actState = m_state; 00231 m_critical.Leave(); 00232 00233 //zde uz externi vlakno muze menit stav jednotky, to se projevi pripadne v dalsim kroku iterace 00234 00235 switch(actState) 00236 { 00237 //jednotka nic nedela - k tomuto by teoreticky nemelo dojit, protoze tento stav znamena ukonceni 00238 //hlavni smycky vlakna - viz staticka metoda TSimpleUnitThread 00239 case ENUM_UNIT_STOP: 00240 { 00241 } 00242 break; 00243 00244 //nacteni noveho snimku 00245 case ENUM_UNIT_LOADFRAME: 00246 { 00247 //nacteme novy snimek 00248 TFrame * frame = NULL; 00249 if( m_lockFrame ) 00250 { 00251 //musime ziskat zamceny snimek 00252 frame = m_dispatcher->GetLockedFrame(); 00253 } 00254 else 00255 { 00256 //jednotka snimky nezamyka 00257 frame = m_dispatcher->GetFrame(); 00258 } 00259 00260 if(frame) 00261 { 00262 //ziskali jsme snimek 00263 //pokud existuje nejaky predchozi snimek zjistime zda se nejedna o identicke snimky 00264 if(m_frame) 00265 { 00266 //zjistime zda se jedna o novejsi snimek 00267 if( frame->GetTimestamp() != m_frame->GetTimestamp() ) 00268 { 00269 //ano - toto je novejsi (jiny) snimek 00270 00271 //rozdil mezi ID snimkku 00272 DWORD lastID = m_frame->GetTimestamp().GetID(); 00273 DWORD newID = frame->GetTimestamp().GetID(); 00274 00275 //spocitame interval zahozenych snimku 00276 if ( newID > lastID ) 00277 { 00278 m_interval = newID - lastID; 00279 } 00280 else 00281 { 00282 //pravdepodobne preteceni 00283 m_interval = 0; 00284 } 00285 00286 //predchozi uvolnime 00287 if( m_lockFrame ) 00288 { 00289 //jednotka drzi zamek 00290 m_frame->ReleaseLock(); 00291 m_frame->Release(); 00292 } 00293 else 00294 { 00295 //pouze reference 00296 m_frame->Release(); 00297 } 00298 //ulozime novy snimek - referenci uz mame (vcetne pripadneho zamku) z metody 00299 //dispatcheru 00300 m_frame = frame; 00301 00302 //pokud mame novy snimek tak prejdeme znovu do stavu zpracovavani snimku 00303 //musi platit aktualni stav ENUM_UNIT_LOADFRAME abychom mohli prejit do ENUM_UNIT_WORK 00304 //toto se muze zmenit pomoci metody Stop ktera zmeni stav na ENUM_UNIT_FINISHWORK 00305 m_critical.Enter(); 00306 if ( m_state == ENUM_UNIT_LOADFRAME ) 00307 { 00308 m_state = ENUM_UNIT_WORK; 00309 } 00310 m_critical.Leave(); 00311 } 00312 else 00313 { 00314 //ne - snimky jsou stejne - pokracujeme v nacitani snimku 00315 //uvolnime referenci na ziskany snimek 00316 if(m_lockFrame) 00317 { 00318 frame->ReleaseLock(); 00319 frame->Release(); 00320 } 00321 else 00322 { 00323 frame->Release(); 00324 } 00325 00326 //todo - mozna pridat nejaky cekaci stav 00327 Sleep(10); 00328 } 00329 } 00330 else // if ( m_frame ) 00331 { 00332 //novy snimek (pravdepodobne prvni) 00333 m_frame = frame; 00334 00335 //prechod do noveho stavu pokud jednotka nechce skoncit 00336 m_critical.Enter(); 00337 if ( m_state == ENUM_UNIT_LOADFRAME ) 00338 { 00339 // ok - jednotka ma stale pracovat 00340 m_state = ENUM_UNIT_WORK; 00341 } 00342 m_critical.Leave(); 00343 00344 // predchozi snimek nebyl k dispozici a interval je tedy 0 00345 m_interval = 0; 00346 } 00347 } 00348 else // if ( frame ) 00349 { 00350 //zadny snimek neprisel 00351 } 00352 } 00353 break; 00354 00355 //procesor zpracovava snimek 00356 case ENUM_UNIT_WORK: 00357 { 00358 //virtualni metoda zpracuje snimek tak jak je reimplementovana 00359 //zde musi byt vzdy nacten snimek !!! 00360 this->m_unit->ProcessFrame( m_frame ); 00361 00362 //snimek bude uvolnen bud pri nacitani dalsiho snimku nebo pri zastaveni jednotky 00363 //snimek potrebujeme pro porovnani s dalsim nactenym snimkem, proto ho zde nemuze uvolnit 00364 00365 //musime znovu nacist snimek pokud nebyla volana metoda Stop 00366 //podminene tedy prechazime do stavu ENUM_UNIT_LOADFRAME 00367 //Volani stop by zpusobilo zmenu stavu na ENUM_UNIT_FINISHWORK a tim by byla v pristim cyklu 00368 //prace jednotka dokoncena 00369 m_critical.Enter(); 00370 if( m_state == ENUM_UNIT_WORK ) 00371 { 00372 m_state = ENUM_UNIT_LOADFRAME; 00373 } 00374 m_critical.Leave(); 00375 } 00376 break; 00377 00378 //ukonceni veskere cinnosti a prechod do stavu ENUM_UNIT_STOP 00379 //tento stav nastane po zavolani metody Stop behem ENUM_UNIT_LOADFRAME nebo ENUM_UNIT_WORK 00380 case ENUM_UNIT_FINISHWORK: 00381 { 00382 m_critical.Enter(); 00383 m_state = ENUM_UNIT_STOP; 00384 m_critical.Leave(); 00385 } 00386 break; 00387 00388 //k tomuto by nemelo nikdy dojit 00389 default: 00390 { 00391 //jen pojistka 00392 assert(false); 00393 00394 m_critical.Enter(); 00395 m_state = ENUM_UNIT_STOP; 00396 m_critical.Leave(); 00397 } 00398 break; 00399 } 00400 } 00401 //OK 2007-08-25 18:44:43 B04-315B\Tom 00402 00403 // TSimpleUnit 00404 //////////////////////////////////////////////////////////////////////////////// 00405 //////////////////////////////////////////////////////////////////////////////// 00406 ////////////////////////////////////////////////////////////////////////////////