00001
00002
00003 /********************************************************************
00004 Description: The Matrix Thread
00005 part of the 3Dsia project
00006 created: xandi, 270300
00007
00008 History:
00009 date, name, changes, in funtion
00010 060500 xandi added Reasons
00011 280400 xandi changed the request-functions completely
00012 should be almost bugfree now
00013 230400 xandi added many odb access functions
00014 180400 StonedBones added dynamic packet length
00015
00016 ********************************************************************/
00017
00018
00019 #include "protocol.h"
00020 #include "buffer.h"
00021 #include "generic.h"
00022
00023 //#include "frontEnd.h"
00024
00025 #include <stdio.h>
00026 #include <unistd.h>
00027
00028 #include <odb/generic.h>
00029 #include <odb/odatabase.h>
00030 #include <odb/odbadbinary.h>
00031
00032 extern Buffer* matrixBufIn;
00033 extern map<int,Buffer*> clientBufferIn;
00034
00035 /*...................................................................
00036 Description: Matrix Thread (the matrix database in fact..)
00037 Args:
00038 Returns:
00039 Created: xandi, 270300
00040 [ToDo:]
00041 Comments:
00042 Changes:
00043 code cleanup, xandi, 050400
00044 merged globalDatabaseThread with matrixThread into matrixThread, xandi, 060400
00045 added many odb access functions, xandi, 230400
00046 moved it into common/ to make it available to the client, xandi, 230400
00047
00048 -------------------------------------------------------------------*/
00049
00051 struct Position
00052 {
00053 double X;
00054 double Y;
00055 double Z;
00056 };
00057
00058 void* MatrixThread ( void* )
00059 {
00060 CODatabase matrixDB;
00061
00062 map<int,CODBReason*> reasonType;
00063 map<int,CODBClass*> classT; //<------- THIS SHALL BECOME THE REAL CLASSTYPE
00064 map<int,string> classType; //<<----- AND THAT SHALL BECOME OBSOLETE!
00065 map<int,string> atomType;
00066
00067 map<int,long> atomSign;
00068 map<int,int> valueType;
00069
00070 classType[CLT_ENTITY] = "Entity";
00071 classType[CLT_OBJECT] = "Object";
00072
00073 classT[CLT_ENTITY] = matrixDB.NewClass (_T("Entity"));
00074 classT[CLT_OBJECT] = matrixDB.NewClass (_T("Object"));
00075
00076 matrixDB.NewClass (_T(classType[CLT_ENTITY]) );
00077 matrixDB.NewClass (_T(classType[CLT_OBJECT]) );
00078
00079 //the reasonTypes define with which reasons objects are bound together
00080
00081 reasonType[RT_E_PARENT_O] = matrixDB.NewReason( _T("EntityParentOfObject"), classT[CLT_ENTITY], classT[CLT_OBJECT] );
00082 reasonType[RT_E_HOLDING_O] = matrixDB.NewReason( _T("EntityHoldsObject"), classT[CLT_ENTITY], classT[CLT_OBJECT] );
00083 reasonType[RT_O_PARTOF_E] = matrixDB.NewReason( _T("ObjectPartOfEntity"), classT[CLT_OBJECT], classT[CLT_ENTITY] );
00084 reasonType[RT_O_PARENT_O] = matrixDB.NewReason( _T("ObjectParentOfObject"), classT[CLT_OBJECT], classT[CLT_OBJECT] );
00085 reasonType[RT_O_ATTACHED_O] = matrixDB.NewReason( _T("ObjectAttachedToObject"), classT[CLT_OBJECT], classT[CLT_OBJECT] );
00086
00087 //those atomTypes are just to define the name the Atom will have - this can be _anything_ its not so important
00088 atomType[AT_USERNAME] = "Username";
00089 atomType[AT_SOCKET] = "Socket";
00090 atomType[AT_NETADDRESS] = "Netaddress"; //as long as we have ipv4 that will be a dotted quad
00091 atomType[AT_POSITION] = "Position";
00092 atomType[AT_ENTITYTYPE] = "Entitytype";
00093 atomType[AT_3DSIAGRAPH] = "3DsiaGraphical";
00094 atomType[AT_CHATMSG] = "Chatmessage";
00095
00096 //the atomSigns are very important. they are used to identify the type of an atom. at the moment, just one
00097 //atom in an object can have the same atomSign.
00098 atomSign[AT_USERNAME] = 0x00000001;
00099 atomSign[AT_SOCKET] = 0x00000002;
00100 atomSign[AT_NETADDRESS] = 0x00000003;
00101 atomSign[AT_POSITION] = 0x00000004;
00102 atomSign[AT_ENTITYTYPE] = 0x00000005;
00103 atomSign[AT_3DSIAGRAPH] = 0x00000006;
00104 atomSign[AT_CHATMSG] = 0x00000007;
00105
00106 //the valuetype specifies the container-type the atom will have.
00107 valueType[AT_USERNAME] = ODB_TYPE_STRING;
00108 valueType[AT_SOCKET] = ODB_TYPE_LONG;
00109 valueType[AT_NETADDRESS] = ODB_TYPE_LONG;
00110 valueType[AT_POSITION] = ODB_TYPE_BINARY;
00111 valueType[AT_ENTITYTYPE] = ODB_TYPE_STRING;
00112 valueType[AT_3DSIAGRAPH] = ODB_TYPE_BINARY;
00113 valueType[AT_CHATMSG] = ODB_TYPE_STRING;
00114
00115 long userSignSpecific = 0xFFFFFFFF;
00116
00117 cerr << "[mT] Matrix Thread started...\n";
00118
00119 int from;
00120
00121 while (1)
00122 {
00123 if ( !matrixBufIn->isEmpty() )
00124 {
00125 #ifdef DEBUG
00126 fprintf(stderr,"[mT] getting something\n");
00127 #endif
00128 packet* pak = matrixBufIn->read ();
00129 from = pak->h.from;
00130
00131 #ifdef DEBUG
00132 fprintf(stderr,"[mT] and that is packet %d from %d\n",pak->h.header[0],from);
00133 #endif
00134
00135 switch (pak->h.header[0])
00136 {
00137 case ODB_ADD_OBJECT:
00138 {
00139 /****************************************************++
00140 Add an Object to the Database xandi, 220400
00141 ----------------------------------------------------- -
00142 header[1] the class the object shall belong to
00143 header[2] objectID (if >= 0 then try to create with this id)
00144 data objectName
00145 ++*****************************************************/
00146
00147 #ifdef DEBUG2
00148 fprintf(stderr,"[mT] adding object %s - request by %d\n",pak->data.c_str (),from);
00149 #endif
00150
00151 long classID = pak->h.header[1];
00152 long objectID = (long) pak->h.header[2];
00153
00154
00155 CODBObject* poObject = 0;
00156 CODBClass* poClass = (CODBClass*) *matrixDB.GetClass ( _T(classType[classID])).begin(); //gets the pointer to the class with the name defined by classType
00157
00158 if ( objectID >= 0 ) //this is just allowed on client side: the local database of the client uses the same ID foro objects as the database on the server
00159 {
00160 #ifdef DEBUG
00161 fprintf(stderr,"[mT] ObjectID: %d - WARNING: IF ITS NOT THE CLIENT ITS A BUG!!\n",(int)objectID);
00162 #endif
00163
00164
00165 if ( !( poObject = matrixDB.Id2PtrObject ( objectID ) ) ) //Checks if that object already exists
00166 {
00167 #ifdef DEBUG
00168 fprintf(stderr,"[mT] ok, seems the object didn't exist...\n");
00169 fprintf(stderr,"[mT] ID-src: %d, ID-dst: %d\n", objectID, (int)poObject->ID());
00170 #endif
00171
00172 poObject = new CODBObject ( objectID, false); //creates the object with the given ID
00173 poObject = matrixDB.Add ( poObject ); //adds it to the matrix
00174 }
00175 /*
00176 else
00177 {
00178 //fprintf(stderr,"[mT] WHAT??.. [%p] [%d] this shouldn't be.. <-------------\n",poObject, (int)objectID);
00179 //or should it?
00180 }
00181 */
00182
00183 poObject->ClassSet ( poClass ); //sets the class the object shall belong to
00184
00185 matrixDB.ChangeName ( poObject, _T(pak->data) ); //changes the name of the object
00186
00187 #ifdef DEBUG
00188 fprintf(stderr,"[mT] pak-data is %s and %d bytes long\n",pak->data.c_str(),pak->data.length() );
00189 #endif
00190 }
00191 else
00192 {
00193 poObject = matrixDB.Add ( new CODBObject ( _T(pak->data), poClass ) ); //creates a new object with a new ID and adds it to the matrix
00194 #ifdef DEBUG
00195 fprintf(stderr,"[mT] created a new object with the ID: %d\n",(int)poObject->ID());
00196 #endif
00197 }
00198
00199
00200 delete pak;
00201 packet* xpak = new packet;
00202
00203 xpak->h.header[0] = PROT_ADD_OBJECT_REPLY;
00204 xpak->h.header[1] = poObject->ID();
00205 xpak->h.header[2] = classID;
00206
00207 clientBufferIn[from]->write ( xpak ); //answers the clientstub
00208
00209 #ifdef DEBUG2
00210 poObject->Dump(); //JUST FOR DEBUG, KICK ME!
00211 #endif
00212 break;
00213 }
00214
00215
00216
00217 case ODB_ADD_ATOM:
00218 {
00219 /****************************************************++
00220 Add a new atom to an object xandi, 230400
00221 ----------------------------------------------------- -
00222 header[1] the type of atom (String, binary, c3dpoint, int..)
00223 header[2] the object the atom shall be attached to
00224 header[3] the group of atoms this one shall belong to (usersign)
00225 header[4] atomID
00226 data the value of the atom;
00227 ++*****************************************************/
00228
00229 long objectID = (long) pak->h.header[2];
00230 long aType = (long) pak->h.header[3];
00231 long atomID = (long) pak->h.header[4];
00232
00233 #ifdef DEBUG
00234 fprintf (stderr,"[mT] adding atom (type %li) to object %li - request from %d\n", aType, objectID, from );
00235 #endif
00236
00237 CODBObject* poObject = matrixDB.Id2PtrObject(objectID); //gets the object which matches the ID
00238
00239 if ( !poObject ) //don't have that object THAT IS CONSIDERED AS A BUG IF THAT HAPPENS!!
00240 {
00241 fprintf(stderr,"[mT] requested object %d not found -- requested by (%d)\n",pak->h.header[2],from);
00242
00243 delete pak;
00244 pak = 0;
00245 // exit(1); //Actually i should do it.. don't know..
00246 break;
00247 }
00248
00249 CVectorAtom oVA = poObject->AtomGet ( atomSign[aType], userSignSpecific ); //get the atom that matches exactly the usersign
00250
00251 CODBAtom* poAtom = 0;
00252
00253 if ( oVA.size() > 0 ) //there is already an atom with that usersign connected to that object
00254 {
00255 if ( oVA.size() != 1 ) //THIS must not be right now.. later we are planning to allow that
00256 {
00257 fprintf(stderr,"[mT] there is more than one atom of the same type in one object..!?!\n");
00258 exit(1); //???????????
00259 //break;
00260 }
00261 else
00262 {
00263 #ifdef DEBUG
00264 fprintf(stderr,"Ok, this atom did exist, it can be used\n");
00265 #endif
00266
00267 CVectorAtom::iterator it = oVA.begin();
00268 poAtom = (*it);
00269 }
00270 }
00271 else //there is no atom with that usersign yet
00272 {
00273 #ifdef DEBUG
00274 fprintf(stderr,"\n");
00275 #endif
00276 if ( atomID >= 0 )
00277 {
00278 #ifdef DEBUG
00279 fprintf(stderr,"[mT] If this is on server-side it must not be!!!\n");
00280 #endif
00281 if ( ( poAtom = matrixDB.Id2PtrAtom(atomID) ) ) //checks if the atom with that ID already exists (JUST ALLOWED CLIENT-SIDE!!)
00282 {
00283 #ifdef DEBUG
00284 fprintf(stderr,"[mT] if thats on the client its all right... but if not - WTF??\n");
00285 #endif
00286 }
00287 else
00288 {
00289 poAtom = matrixDB.Add ( new CODBAtom ( atomID ) ); //Creates an atom with a given ID and adds it to the database
00290 }
00291 }
00292 else
00293 {
00294 poAtom = matrixDB.Add ( new CODBAtom () ); //Creates an empty atom and adds it to the database - the database will assign an ID to the atom
00295 }
00296
00297 }
00298
00299 poAtom->NameSet ( _T(atomType[aType]) ); //sets the name of the atom
00300 poAtom->UserSignSet ( atomSign[aType] ); //sets the usersign
00301
00302 int containerType = valueType[aType];
00303
00304 switch ( containerType )
00305 {
00306 case ODB_TYPE_STRING:
00307 {
00308 *poAtom = _T(pak->data);
00309
00310 break;
00311 }
00312
00313 case ODB_TYPE_BINARY:
00314 {
00315 long temp = pak->data.length();
00316 *poAtom = new CODBADBinary ( const_cast<char*>(pak->data.data()), temp );
00317 break;
00318 }
00319
00320 case ODB_TYPE_LONG:
00321 {
00322 long tempLong;
00323 memcpy ( &tempLong, pak->data.data(), sizeof(long) );
00324 *poAtom = tempLong;
00325 break;
00326 }
00327
00328 /*
00329 case ODB_TYPE_3DPOINT:
00330 {
00331 double temp[3];
00332 memcpy ( &temp, pak->data.data() );
00333
00334 break;
00335 }
00336 */
00337
00338 default:
00339 {
00340 fprintf ( stderr,"[mT] adding atom of unknown containertype (%d)! not yet implemented or just a mistake by (%d)!\n",containerType,from);
00341 break;
00342 }
00343 }
00344
00345 #ifdef DEBUG
00346 fprintf(stderr,"[mT] ------------ ID of added Atom: %d\n",(int)poAtom->ID());
00347 #endif
00348
00349 poObject->AtomAdd ( poAtom ); //adds atom to the object
00350
00351 delete pak;
00352 pak = 0;
00353 break;
00354 }
00355
00356
00357
00358
00359 case ODB_GET_ALL_CHANGED:
00360 {
00361 /****************************************************++
00362 Request of all new/changed things, xandi, 290400
00363 those IDs are sent seperately to the clientstub
00364 ----------------------------------------------------- -
00365 header[1] nothing yet...
00366 TimeStamp the last time checked
00367 ++*****************************************************/
00368
00369 //fprintf(stderr,"GetAllChanged: %d.%d\n",pak->h.TimeStamp.tv_sec,pak->h.TimeStamp.tv_usec);
00370 CVectorRoot oVR = matrixDB.GetThingsChanged ( pak->h.TimeStamp ); //gets all things that have changed since the last check..
00371
00372 delete pak;
00373
00374 for ( CVectorRoot::iterator it = oVR.begin(); it != oVR.end(); ++it )
00375 {
00376 packet* xpak = new packet;
00377
00378 long rttiInfo = (*it)->InfoGetRtti(); //gets the information which type of THING that is..
00379
00380 switch ( rttiInfo )
00381 {
00382 case _Object: //its an object!! ;)
00383 {
00384 CODBObject* poObject = (CODBObject*)*it;
00385
00386 #ifdef DEBUG3
00387 cerr << "[mT] rtti-info -> _Object " << poObject->ID() << "\n";
00388 #endif
00389
00390 #ifdef DEBUG
00391 cerr << "[mT] rtti-info -> _Object\n";
00392 poObject->Dump();
00393 #endif
00394
00395 CODBClass* poClass = poObject->ClassGet(); //gets the pointer to the class
00396
00397 string className = poClass->NameGet(); //gets the name of the class
00398
00399 xpak->h.header[2] = -1;
00400
00401 typedef map<int,string>::const_iterator classIt;
00402 for ( classIt c = classType.begin(); c != classType.end(); ++c) //tries to find the classtype ID connected to the name
00403 {
00404 if ( c->second == className )
00405 {
00406 xpak->h.header[2] = c->first;
00407 break;
00408 }
00409 }
00410
00411 if ( xpak->h.header[2] == -1 )
00412 {
00413 fprintf(stderr,"[mT] The ClassType does not exist??? WTF??\n");
00414 exit(1);
00415 }
00416
00417 xpak->h.header[0] = PROT_GET_ALL_OBJECTS_REPLY;
00418 xpak->h.header[1] = poObject->ID();
00419
00420 clientBufferIn[from]->write ( xpak );
00421
00422 break;
00423 }
00424
00425 case _Atom:
00426 {
00427 CODBAtom* poAtom = (CODBAtom*)*it;
00428
00429 #ifdef DEBUG2
00430 cerr << "[mT] rtti-info -> _Atom " << poAtom->ID() << "\n";
00431 #endif
00432
00433 long atomUserSign = poAtom->UserSignGet();
00434
00435
00436 long objectID = -1;
00437
00438 CMapReferencing& cRM = const_cast<CMapReferencing&>( poAtom->ParentGet());
00439
00440 for ( CMapReferencing::iterator c = cRM.begin(); c != cRM.end(); ++c )
00441 {
00442 long parentRttiInfo = c->first->InfoGetRtti ();
00443
00444 switch ( parentRttiInfo )
00445 {
00446 case _Object:
00447 {
00448 #ifdef DEBUG2
00449 cerr << "[mT] parteninfo: _Object\n";
00450 #endif
00451 objectID = c->first->ID();
00452 break;
00453 }
00454 default:
00455 {
00456 cerr << "[mT] the atom has other parents than an Object - Handler not yet implemented!\n";
00457 break;
00458 }
00459 }
00460
00461 }
00462
00463
00464 if ( objectID == -1 )
00465 {
00466 #ifdef DEBUG2
00467 cerr << "[mT] The Atom does not have any parents at all!\n";
00468 #endif
00469 delete xpak;
00470 break;
00471 }
00472
00473 xpak->h.header[0] = PROT_GET_ALL_ATOMS_REPLY;
00474 xpak->h.header[1] = poAtom->ID();
00475 xpak->h.header[2] = (int) objectID;
00476 xpak->h.header[3] = -1;
00477
00478
00479 typedef map<int,long>::const_iterator atomIt;
00480
00481 for ( atomIt a = atomSign.begin(); a != atomSign.end(); ++a)
00482 {
00483 if ( a->second == atomUserSign )
00484 {
00485 xpak->h.header[3] = a->first;
00486 break;
00487 }
00488 }
00489 if ( xpak->h.header[3] == -1 )
00490 {
00491 fprintf(stderr,"[mT] this must not be!! there was an atom of unknown type in the database..\n");
00492 exit(1);
00493 }
00494
00495 #ifdef DEBUG2
00496 fprintf(stderr,"[mT] Atom %d of object %d with type %d\n",xpak->h.header[1],xpak->h.header[2],xpak->h.header[3]);
00497 fprintf(stderr,"---------------[%d]-[%d]-------------\n",xpak->h.header[1],xpak->h.header[2],xpak->h.header[3]);
00498 #endif
00499
00500 clientBufferIn[from]->write ( xpak );
00501
00502 break;
00503 }
00504
00505
00506 case _Reason:
00507 {
00508 break;
00509 }
00510
00511 default:
00512 {
00513 #ifdef DEBUG2
00514 cerr << "[mT] rtti type unknown!\n";
00515 #endif
00516 delete xpak;
00517 break;
00518 }
00519
00520 }
00521
00522 }
00523 break;
00524 }
00525
00526
00527 case ODB_GET_OBJECT:
00528 {
00529 /****************************************************++
00530 Request an object from the database xandi, 230400
00531 ----------------------------------------------------- -
00532 header[1] ID of object
00533 ++*****************************************************/
00534
00535 CODBObject* poObject = matrixDB.Id2PtrObject(pak->h.header[1]);
00536 #ifdef DEBUG
00537 fprintf(stderr,"[mT] ODB_GET_OBJECT %d - %p\n",pak->h.header[1],poObject);
00538 #endif
00539
00540 pak->h.header[0] = PROT_GET_OBJECT_REPLY;
00541 pak->data = poObject->NameGet();
00542 //anything more?? (ID is already in header[1]);
00543
00544 clientBufferIn[from]->write ( pak );
00545 #ifdef DEBUG
00546 fprintf(stderr,"[mT] ODB_GET_OBJECT successful...\n");
00547 #endif
00548 break;
00549 }
00550
00551
00552
00553
00554 case ODB_GET_ATOM:
00555 {
00556 /****************************************************++
00557 Request an atom from an object xandi, 230400
00558 ----------------------------------------------------- -
00559 header[1] the ID of the Atom
00560 header[2] the ID of its Object
00561 header[3] type of atom (usersign)
00562 ++*****************************************************/
00563
00564 long atomID = pak->h.header[1];
00565 long objectID = pak->h.header[2];
00566 long aType = pak->h.header[3];
00567
00568 delete pak;
00569 pak = 0;
00570
00571 CODBAtom* poAtom = matrixDB.Id2PtrAtom(atomID);
00572
00573 if ( !poAtom )
00574 {
00575 fprintf(stderr,"[mT] strange, the requested atom does not exsist\n");
00576 exit(1);
00577 }
00578 else
00579 {
00580
00581 packet* xpak = new packet;
00582
00583 unsigned char* tempBuffer;
00584 long sizeOfBuffer = poAtom->BinarySizeGet();
00585 long tempLength;
00586
00587 tempBuffer = new unsigned char[sizeOfBuffer]; //+1 oder nicht, das ist hier die frage..
00588
00589 #ifdef DEBUG
00590 fprintf(stderr,"[mT] length of binary stream: %d\n",(int)sizeOfBuffer);
00591 #endif
00592
00593 tempLength = poAtom->BinaryDataGet ( tempBuffer, sizeOfBuffer );
00594
00595 #ifdef DEBUG
00596 fprintf(stderr,"[mT] real length of binary stream: %d\n",(int)tempLength);
00597 #endif
00598
00599 xpak->h.header[0] = PROT_GET_ATOM_REPLY;
00600 xpak->h.header[1] = (int) objectID;
00601 xpak->h.header[2] = aType;
00602 xpak->h.header[3] = poAtom->ID();
00603
00604 xpak->data.assign ( (char*) tempBuffer, sizeOfBuffer );
00605
00606 #ifdef DEBUG
00607 fprintf(stderr,"[mT] content: [ %li - %d ]\n",aType,xpak->h.header[3]);
00608 #endif
00609
00610 xpak->h.header[4] = valueType[aType];
00611
00612 clientBufferIn[from]->write ( xpak );
00613
00614 delete tempBuffer;
00615 }
00616 break;
00617 }
00618
00619 case ODB_ADD_REASON:
00620 {
00621 /****************************************************++
00622 Add a Reson to an object xandi, 060500
00623 ----------------------------------------------------- -
00624 header[1] the ID of the Object the reason should be attached to
00625 header[2] the ID of the Object it is bound with some reason to
00626 header[3] type of reason
00627 ++*****************************************************/
00628
00629 long objectIDa = (long) pak->h.header[1];
00630 long objectIDb = (long) pak->h.header[2];
00631 int reason = pak->h.header[3];
00632
00633 CODBObject* poObjectA = matrixDB.Id2PtrObject ( objectIDa );
00634 CODBObject* poObjectB = matrixDB.Id2PtrObject ( objectIDb );
00635
00636 if ( poObjectA && poObjectB )
00637 {
00638 poObjectA->Link ( poObjectB, reasonType[reason] );
00639 }
00640
00641 else
00642 {
00643 #ifdef DEBUG
00644 fprintf(stderr,"[mT.odbAddReason] no no no, that doesn't work.. one of the objects does not exist\n");
00645 #endif
00646 }
00647
00648 delete pak;
00649 break;
00650 }
00651
00652 case ODB_REMOVE_REASON:
00653 {
00654 /****************************************************++
00655 Remove a Reson from an object xandi, 060500
00656 ----------------------------------------------------- -
00657 header[1] the ID of the Object the reason should be removed from
00658 header[2] the ID of the Object it is bound with some reason to
00659 header[3] type of reason
00660 ++*****************************************************/
00661
00662 long objectIDa = (long) pak->h.header[1];
00663 long objectIDb = (long) pak->h.header[2];
00664 int reason = pak->h.header[3];
00665
00666 CODBObject* poObjectA = matrixDB.Id2PtrObject ( objectIDa );
00667 CODBObject* poObjectB = matrixDB.Id2PtrObject ( objectIDb );
00668
00669 if ( poObjectA && poObjectB )
00670 {
00671 poObjectA->LinkRemove ( poObjectB, reasonType[reason] );
00672 }
00673
00674 else
00675 {
00676 #ifdef DEBUG
00677 fprintf(stderr,"[mT.odbAddReason] no no no, that doesn't work.. one of the objects does not exist\n");
00678 #endif
00679 }
00680
00681 delete pak;
00682 break;
00683 }
00684
00685 default:
00686 {
00687 fprintf(stderr,"CANT BE!!!!!!!!!\n");
00688 break;
00689 }
00690 }
00691 }
00692 }
00693 } //void matrixThread ( void )
00694
00695
00696
00697
00698
00699 /***********************************************************************************************+++
00700 +******************************************************************************************+
00701 +*************************************************************************************+
00702 OBSOLETE
00703 +*************************************************************************************+
00704 ++****************************************************************************************++
00705 ++**********************************************************************************************+*/
00706
00707 /* [snip] removed that :) */