nico@207: nico@207:
nico@207:00001 /* nico@210: 00002 This file is part of CanFestival, a library implementing CanOpen nico@210: 00003 Stack. nico@210: 00004 nico@210: 00005 Copyright (C): Edouard TISSERANT and Francis DUPIN nico@210: 00006 nico@210: 00007 See COPYING file for copyrights details. nico@210: 00008 nico@210: 00009 This library is free software; you can redistribute it and/or nico@210: 00010 modify it under the terms of the GNU Lesser General Public nico@210: 00011 License as published by the Free Software Foundation; either nico@210: 00012 version 2.1 of the License, or (at your option) any later version. nico@210: 00013 nico@210: 00014 This library is distributed in the hope that it will be useful, nico@210: 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of nico@210: 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU nico@210: 00017 Lesser General Public License for more details. nico@210: 00018 nico@210: 00019 You should have received a copy of the GNU Lesser General Public nico@210: 00020 License along with this library; if not, write to the Free Software nico@210: 00021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 nico@210: 00022 USA nico@210: 00023 */ nico@210: 00024 #include "pdo.h" nico@210: 00025 #include "objacces.h" nico@210: 00026 #include "canfestival.h" nico@210: 00027 nico@210: 00037 UNS8 sendPDO(CO_Data* d, s_PDO pdo, UNS8 req) nico@210: 00038 { nico@210: 00039 UNS8 i; nico@210: 00040 if( d->nodeState == Operational ) { nico@210: 00041 Message m; nico@210: 00042 nico@210: 00044 m.cob_id.w = pdo.cobId & 0x7FF; nico@210: 00046 if ( req == NOT_A_REQUEST ) { nico@210: 00047 UNS8 i; nico@210: 00048 m.rtr = NOT_A_REQUEST; nico@210: 00049 m.len = pdo.len; nico@210: 00052 for (i = 0 ; i < pdo.len ; i++) nico@210: 00053 m.data[i] = pdo.data[i]; nico@210: 00054 } nico@210: 00055 else { nico@210: 00056 m.rtr = REQUEST; nico@210: 00057 m.len = 0; nico@210: 00058 } nico@207: 00059 nico@210: 00060 MSG_WAR(0x3901, "sendPDO cobId :", m.cob_id.w); nico@210: 00061 MSG_WAR(0x3902, " Nb octets : ", m.len); nico@210: 00062 for (i = 0 ; i < m.len ; i++) { nico@210: 00063 MSG_WAR(0x3903," data : ", m.data[i]); nico@210: 00064 } nico@210: 00065 nico@210: 00066 return canSend(d->canHandle,&m); nico@210: 00067 } nico@210: 00068 return 0xFF; nico@210: 00069 } nico@210: 00070 nico@210: 00079 UNS8 PDOmGR(CO_Data* d, UNS32 cobId) nico@210: 00080 { nico@210: 00081 UNS8 res; nico@210: 00082 UNS8 i; nico@210: 00083 s_PDO pdo; nico@210: 00084 nico@210: 00085 MSG_WAR(0x3905, "PDOmGR",0); nico@210: 00086 nico@210: 00089 pdo.cobId = cobId; nico@210: 00090 pdo.len = d->process_var.count; nico@210: 00092 /* Ce memcpy devrait tre portable */ nico@210: 00093 for ( i = 0 ; i < pdo.len ; i++) nico@210: 00094 pdo.data[i] = d->process_var.data[i]; nico@210: 00095 nico@210: 00096 res = sendPDO(d, pdo, NOT_A_REQUEST); nico@210: 00097 nico@210: 00098 return res; nico@210: 00099 } nico@210: 00100 nico@210: 00101 #if 0 nico@210: 00102 /*********************************************************************/ nico@210: 00103 /* TODO : implement bit mapping */ nico@210: 00104 /*********************************************************************/ nico@207: 00105 nico@210: 00106 UNS8 buildPDO(CO_Data* d, UNS16 index) nico@210: 00107 { /* DO NOT USE MSG_ERR because the macro may send a PDO -> infinite loop if it fails. */ nico@210: 00108 UNS16 ind; nico@210: 00109 UNS8 subInd; nico@210: 00110 nico@210: 00111 UNS8 * pMappingCount = NULL; /* count of mapped objects... */ nico@210: 00112 /* pointer to the var which is mapped to a pdo */ nico@210: 00113 /* void * pMappedAppObject = NULL; */ nico@210: 00114 /* pointer fo the var which holds the mapping parameter of an mapping entry */ nico@210: 00115 nico@210: 00116 UNS32 * pMappingParameter = NULL; nico@210: 00117 nico@210: 00118 UNS8 Size; nico@210: 00119 UNS8 dataType; nico@210: 00120 UNS8 offset; nico@210: 00121 UNS16 offsetObjdict; nico@210: 00122 UNS16 offsetObjdictPrm; nico@210: 00123 UNS32 objDict; nico@210: 00124 nico@210: 00125 subInd=(UNS8)0x00; nico@210: 00126 offset = 0x00; nico@210: 00127 ind = index - 0x1800; nico@210: 00128 nico@210: 00129 MSG_WAR(0x3910,"Prepare PDO to send index :", index); nico@210: 00130 nico@210: 00132 if( d->nodeState != Operational ) { nico@210: 00133 MSG_WAR(0x2911, "Unable to send the PDO (node not in OPERATIONAL mode). Node : ", index); nico@210: 00134 return 0xFF; nico@210: 00135 } nico@210: 00136 offsetObjdictPrm = d->firstIndex->PDO_TRS; nico@210: 00137 offsetObjdict = d->firstIndex->PDO_TRS_MAP; nico@210: 00138 nico@210: 00139 if (offsetObjdictPrm && offsetObjdict) nico@210: 00140 { nico@210: 00142 pMappingCount = (d->objdict + offsetObjdict + ind)->pSubindex[0].pObject; nico@210: 00143 MSG_WAR(0x3912, "Nb maped objects : ",* pMappingCount); nico@210: 00144 MSG_WAR(0x3913, " at index : ", 0x1A00 + ind); nico@210: 00145 while (subInd < *pMappingCount) { nico@210: 00147 pMappingParameter = (d->objdict + offsetObjdict + ind)->pSubindex[subInd + 1].pObject; nico@210: 00148 MSG_WAR(0x3914, "Get the mapping at index : ", (UNS16)0x1A00 + ind); nico@210: 00149 MSG_WAR(0x3915, " subIndex : ", subInd + 1); nico@210: 00150 MSG_WAR(0x3916, " value : ", *(UNS32 *)pMappingParameter); nico@210: 00152 Size = ((UNS8)(((*pMappingParameter) & 0xFF) >> 3)); nico@210: 00153 objDict = getODentry(d, (UNS16)((*pMappingParameter) >> 16), nico@210: 00154 (UNS8)(((*pMappingParameter) >> 8 ) & 0x000000FF), nico@210: 00155 (void *)&d->process_var.data[offset], &Size, &dataType, 0 ); nico@210: 00156 nico@210: 00157 if (objDict != OD_SUCCESSFUL) { nico@210: 00158 MSG_WAR(0x2919, "error accessing to the mapped var : ", subInd + 1); nico@210: 00159 MSG_WAR(0x2920, " Mapped at index : ", (*pMappingParameter) >> 16); nico@210: 00160 MSG_WAR(0x2921, " subindex : ", ((*pMappingParameter) >> 8 ) & 0xFF); nico@210: 00161 return 0xFF; nico@210: 00162 } nico@210: 00163 nico@210: 00164 offset += Size; nico@210: 00165 d->process_var.count = offset; nico@210: 00166 subInd++; nico@210: 00167 } nico@210: 00168 } nico@210: 00169 return 0; nico@210: 00170 } nico@210: 00171 #endif nico@210: 00172 nico@210: 00181 UNS8 sendPDOrequest( CO_Data* d, UNS32 cobId ) nico@210: 00182 { nico@210: 00183 UNS32 * pwCobId; nico@210: 00184 UNS16 offset; nico@210: 00185 UNS16 lastIndex; nico@210: 00186 UNS8 err; nico@210: 00187 nico@210: 00188 MSG_WAR(0x3930, "sendPDOrequest ",0); nico@210: 00192 offset = d->firstIndex->PDO_RCV; nico@210: 00193 lastIndex = d->lastIndex->PDO_RCV; nico@210: 00194 if (offset) nico@210: 00195 while (offset <= lastIndex) { nico@210: 00197 pwCobId = d->objdict[offset].pSubindex[1].pObject; nico@210: 00198 nico@210: 00199 if ( *pwCobId == cobId ) { nico@210: 00200 s_PDO pdo; nico@210: 00201 pdo.cobId = *pwCobId; nico@210: 00202 pdo.len = 0; nico@210: 00203 err = sendPDO(d, pdo, REQUEST); nico@210: 00204 return err; nico@210: 00205 } nico@210: 00206 offset++; nico@210: 00207 } nico@210: 00208 MSG_WAR(0x1931, "sendPDOrequest : COBID not found : ", cobId); nico@210: 00209 return 0xFF; nico@210: 00210 } nico@210: 00211 nico@210: 00212 nico@210: 00221 UNS8 proceedPDO(CO_Data* d, Message *m) nico@210: 00222 { nico@210: 00223 UNS8 numPdo; nico@210: 00224 UNS8 numMap; nico@210: 00225 UNS8 i; nico@210: 00226 UNS8 * pMappingCount = NULL; nico@210: 00231 UNS32 * pMappingParameter = NULL; nico@210: 00232 UNS8 * pTransmissionType = NULL; nico@210: 00234 UNS32 * pwCobId = NULL; nico@210: 00235 UNS8 Size; nico@210: 00236 UNS8 dataType; nico@210: 00237 UNS8 offset; nico@210: 00238 UNS8 status; nico@210: 00239 UNS32 objDict; nico@210: 00240 UNS16 offsetObjdict; nico@210: 00241 UNS16 lastIndex; nico@210: 00242 status = state1; nico@210: 00243 nico@210: 00244 MSG_WAR(0x3935, "proceedPDO, cobID : ", ((*m).cob_id.w & 0x7ff)); nico@210: 00245 offset = 0x00; nico@210: 00246 numPdo = 0; nico@210: 00247 numMap = 0; nico@210: 00248 if((*m).rtr == NOT_A_REQUEST ) { nico@210: 00250 offsetObjdict = d->firstIndex->PDO_RCV; nico@210: 00251 lastIndex = d->lastIndex->PDO_RCV; nico@210: 00252 nico@210: 00254 if(offsetObjdict) nico@210: 00255 while (offsetObjdict <= lastIndex) { nico@210: 00256 nico@210: 00257 switch( status ) { nico@210: 00258 nico@210: 00259 case state1: nico@210: 00262 for ( i = 0 ; i < m->len ; i++) nico@210: 00263 d->process_var.data[i] = m->data[i]; nico@210: 00264 d->process_var.count = (*m).len; nico@210: 00265 nico@210: 00266 status = state2; nico@210: 00267 break; nico@210: 00268 nico@210: 00269 case state2: nico@210: 00272 pwCobId = d->objdict[offsetObjdict].pSubindex[1].pObject; nico@210: 00276 if ( *pwCobId == (*m).cob_id.w ){ nico@210: 00278 status = state4; nico@210: 00279 MSG_WAR(0x3936, "cobId found at index ", 0x1400 + numPdo); nico@210: 00280 break; nico@210: 00281 } nico@210: 00282 else { nico@210: 00285 numPdo++; nico@210: 00286 offsetObjdict++; nico@210: 00287 status = state2; nico@210: 00288 break; nico@210: 00289 } nico@210: 00290 nico@210: 00291 case state4: nico@210: 00294 offsetObjdict = d->firstIndex->PDO_RCV_MAP; nico@210: 00295 lastIndex = d->lastIndex->PDO_RCV_MAP; nico@210: 00296 pMappingCount = (d->objdict + offsetObjdict + numPdo)->pSubindex[0].pObject; nico@210: 00297 numMap = 0; nico@210: 00298 while (numMap < *pMappingCount) { nico@210: 00299 UNS8 tmp[]= {0,0,0,0,0,0,0,0}; nico@210: 00300 UNS8 ByteSize; nico@210: 00301 pMappingParameter = (d->objdict + offsetObjdict + numPdo)->pSubindex[numMap + 1].pObject; nico@210: 00302 if (pMappingParameter == NULL) { nico@210: 00303 MSG_ERR(0x1937, "Couldn't get mapping parameter : ", numMap + 1); nico@210: 00304 return 0xFF; nico@210: 00305 } nico@210: 00313 Size = (UNS8)(*pMappingParameter); nico@207: 00314 nico@210: 00316 CopyBits(Size, (UNS8*)&d->process_var.data[offset>>3], offset%8, 0, ((UNS8*)tmp), 0, 0); nico@210: 00317 nico@210: 00318 ByteSize = 1 + ((Size - 1) >> 3); /*1->8 => 1 ; 9->16 => nico@210: 00319 2, ... */ nico@210: 00320 nico@210: 00321 objDict = setODentry(d, (UNS16)((*pMappingParameter) >> 16), nico@210: 00322 (UNS8)(((*pMappingParameter) >> 8 ) & 0xFF), nico@210: 00323 tmp, &ByteSize, 0 ); nico@210: 00324 nico@210: 00325 if(objDict != OD_SUCCESSFUL) { nico@210: 00326 MSG_ERR(0x1938, "error accessing to the mapped var : ", numMap + 1); nico@210: 00327 MSG_WAR(0x2939, " Mapped at index : ", (*pMappingParameter) >> 16); nico@210: 00328 MSG_WAR(0x2940, " subindex : ", ((*pMappingParameter) >> 8 ) & 0xFF); nico@210: 00329 return 0xFF; nico@210: 00330 } nico@210: 00331 nico@210: 00332 MSG_WAR(0x3942, "Variable updated with value received by PDO cobid : ", m->cob_id.w); nico@210: 00333 MSG_WAR(0x3943, " Mapped at index : ", (*pMappingParameter) >> 16); nico@210: 00334 MSG_WAR(0x3944, " subindex : ", ((*pMappingParameter) >> 8 ) & 0xFF); nico@210: 00336 offset += Size; nico@210: 00337 numMap++; nico@210: 00338 } nico@210: 00340 offset=0x00; nico@210: 00341 numMap = 0; nico@210: 00342 return 0; nico@210: 00343 nico@210: 00344 } nico@210: 00345 } nico@210: 00346 } nico@210: 00347 else if ((*m).rtr == REQUEST ){ nico@210: 00348 MSG_WAR(0x3946, "Receive a PDO request cobId : ", m->cob_id.w); nico@210: 00349 status = state1; nico@210: 00350 offsetObjdict = d->firstIndex->PDO_TRS; nico@210: 00351 lastIndex = d->lastIndex->PDO_TRS; nico@210: 00352 if(offsetObjdict) while( offsetObjdict <= lastIndex ){ nico@210: 00355 switch( status ){ nico@210: 00356 nico@210: 00357 case state1: nico@210: 00360 pwCobId = (d->objdict + offsetObjdict)->pSubindex[1].pObject; nico@210: 00361 if ( *pwCobId == (*m).cob_id.w ) { nico@210: 00362 status = state4; nico@210: 00363 break; nico@210: 00364 } nico@210: 00365 else { nico@210: 00366 numPdo++; nico@210: 00367 offsetObjdict++; nico@210: 00368 } nico@210: 00369 status = state1; nico@210: 00370 break; nico@210: 00371 nico@210: 00372 nico@210: 00373 case state4: nico@210: 00374 pTransmissionType = d->objdict[offsetObjdict].pSubindex[2].pObject; nico@210: 00375 if ( (*pTransmissionType == TRANS_RTR) || (*pTransmissionType == TRANS_RTR_SYNC ) || (*pTransmissionType == TRANS_EVENT) ) { nico@210: 00376 status = state5; nico@210: 00377 break; nico@210: 00378 } nico@210: 00379 else { nico@210: 00382 MSG_WAR(0x2947, "PDO is not to send on request : ", m->cob_id.w); nico@210: 00383 return 0xFF; nico@210: 00384 } nico@210: 00385 nico@210: 00386 case state5: nico@210: 00387 offsetObjdict = d->firstIndex->PDO_TRS_MAP; nico@210: 00388 lastIndex = d->lastIndex->PDO_TRS_MAP; nico@210: 00389 pMappingCount = (d->objdict + offsetObjdict + numPdo)->pSubindex[0].pObject; nico@210: 00390 numMap = 0; nico@210: 00391 while (numMap < *pMappingCount) { nico@210: 00392 pMappingParameter = (d->objdict + offsetObjdict + numPdo)->pSubindex[numMap + 1].pObject; nico@210: 00394 Size = ((UNS8)(((*pMappingParameter) & 0xFF) >> 3)); nico@210: 00395 objDict = getODentry( d, (UNS16)((*pMappingParameter) >> (UNS8)16), nico@210: 00396 (UNS8)(( (*pMappingParameter) >> (UNS8)8 ) & 0xFF), nico@210: 00397 (void *)&d->process_var.data[offset], &Size, &dataType, 0 ); nico@210: 00398 if (objDict != OD_SUCCESSFUL) { nico@210: 00399 MSG_ERR(0x1948, "error accessing to the mapped var : ", numMap + 1); nico@210: 00400 MSG_WAR(0x2949, " Mapped at index : ", (*pMappingParameter) >> 16); nico@210: 00401 MSG_WAR(0x2950, " subindex : ", ((*pMappingParameter) >> 8 ) & 0xFF); nico@210: 00402 return 0xFF; nico@210: 00403 } nico@210: 00404 offset += (UNS8) (((*pMappingParameter) & 0xFF) >> 3); nico@210: 00405 d->process_var.count = offset; nico@210: 00406 numMap++; nico@210: 00407 nico@210: 00408 } nico@210: 00409 PDOmGR( d, *pwCobId ); nico@210: 00410 return 0; nico@210: 00411 nico@210: 00412 } nico@210: 00413 } nico@210: 00414 } nico@210: 00416 return 0; nico@210: 00417 } nico@210: 00418 nico@210: 00430 void CopyBits(UNS8 NbBits, UNS8* SrcByteIndex, UNS8 SrcBitIndex, UNS8 SrcBigEndian, UNS8* DestByteIndex, UNS8 DestBitIndex, UNS8 DestBigEndian) nico@210: 00431 { nico@210: 00434 // boundaries from LSB to MSB. nico@210: 00435 while(NbBits > 0) nico@210: 00436 { nico@210: 00438 INTEGER8 Vect = DestBitIndex - SrcBitIndex; nico@210: 00439 nico@210: 00441 UNS8 Aligned = Vect>0 ? *SrcByteIndex << Vect : *SrcByteIndex >> -Vect; nico@210: 00442 nico@210: 00444 UNS8 BoudaryLimit = (Vect>0 ? 8 - DestBitIndex : 8 - SrcBitIndex ); nico@210: 00445 UNS8 BitsToCopy = BoudaryLimit > NbBits ? NbBits : BoudaryLimit; nico@210: 00446 nico@210: 00448 UNS8 Mask = ((0xff << (DestBitIndex + BitsToCopy)) | (0xff >> (8 - DestBitIndex))); nico@210: 00449 nico@210: 00451 UNS8 Filtered = Aligned & ~Mask; nico@210: 00452 nico@210: 00454 *DestByteIndex &= Mask; nico@210: 00455 nico@210: 00457 *DestByteIndex |= Filtered ; nico@210: 00458 nico@210: 00460 if((SrcBitIndex += BitsToCopy)>7) nico@210: 00461 { nico@210: 00462 SrcBitIndex = 0; nico@210: 00463 SrcByteIndex += (SrcBigEndian ? -1 : 1); nico@210: 00464 } nico@210: 00465 nico@210: 00466 nico@210: 00468 if((DestBitIndex += BitsToCopy)>7) nico@210: 00469 { nico@210: 00470 DestBitIndex = 0; nico@210: 00471 DestByteIndex += (DestBigEndian ? -1 : 1); nico@210: 00472 } nico@210: 00473 nico@210: 00475 NbBits -= BitsToCopy; nico@210: 00476 } nico@210: 00477 nico@210: 00478 } nico@210: 00479 nico@210: 00480 #if 0 nico@210: 00481 nico@210: 00482 /*********************************************************************/ nico@210: 00483 /* TODO : reimplement this using CallBacks nico@210: 00484 */ nico@210: 00485 /*********************************************************************/ nico@210: 00486 nico@210: 00495 UNS8 sendPDOevent( CO_Data* d, void * variable ) nico@210: 00496 { nico@210: 00498 UNS32 objDict = 0; nico@210: 00499 UNS8 ind, sub_ind; nico@210: 00500 UNS8 status; nico@210: 00501 UNS8 offset; nico@210: 00502 UNS8 * pMappingCount = NULL; nico@210: 00503 UNS32 * pMappingParameter = NULL; nico@210: 00504 void * pMappedAppObject = NULL; nico@210: 00505 UNS8 * pTransmissionType = NULL; nico@210: 00507 UNS32 * pwCobId = NULL; nico@210: 00508 UNS8 * pSize; nico@210: 00509 UNS8 size; nico@210: 00510 UNS8 dataType; nico@210: 00511 UNS16 offsetObjdict; nico@210: 00512 UNS16 offsetObjdictPrm; nico@210: 00513 UNS16 lastIndex; nico@210: 00514 UNS8 numMap; nico@210: 00515 ind = 0x00; nico@210: 00516 sub_ind = 1; nico@210: 00517 offset = 0x00; nico@210: 00518 pSize = &size; nico@210: 00519 status = state1; nico@210: 00520 nico@210: 00521 nico@210: 00525 MSG_WAR (0x3960, "sendPDOevent", 0); nico@210: 00526 offsetObjdictPrm = d->firstIndex->PDO_TRS; nico@210: 00527 nico@210: 00528 offsetObjdict = d->firstIndex->PDO_TRS_MAP; nico@210: 00529 lastIndex = d->lastIndex->PDO_TRS_MAP; nico@210: 00530 nico@210: 00531 if (offsetObjdictPrm && offsetObjdict) nico@210: 00533 while(offsetObjdict <= lastIndex){ nico@210: 00535 pTransmissionType = d->objdict[offsetObjdictPrm].pSubindex[2].pObject; nico@210: 00536 if (*pTransmissionType != TRANS_EVENT) { nico@210: 00537 ind++; nico@210: 00538 offsetObjdict++; nico@210: 00539 offsetObjdictPrm++; nico@210: 00540 continue; nico@210: 00541 } nico@210: 00542 pMappingCount = d->objdict[offsetObjdict].pSubindex[0].pObject; nico@210: 00543 numMap = 1; nico@210: 00544 while (numMap <= *pMappingCount) { nico@210: 00545 pMappingParameter = d->objdict[offsetObjdict].pSubindex[numMap].pObject; nico@210: 00547 objDict = getODentry( d, nico@210: 00548 (UNS16)((*pMappingParameter) >> 16), nico@210: 00549 (UNS8)(( (*pMappingParameter) >> (UNS8)8 ) & (UNS32)0x000000FF), nico@210: 00550 (void * *)&pMappedAppObject, pSize, &dataType, 0 ); nico@210: 00551 if( objDict != OD_SUCCESSFUL ) { nico@210: 00552 MSG_WAR(0x2961, "Error in dict. at index : ", nico@210: 00553 (*pMappingParameter) >> (UNS8)16); nico@210: 00554 nico@210: 00555 MSG_WAR(0x2962, " subindex : ", nico@210: 00556 ((*pMappingParameter) >> (UNS8)8 ) & (UNS32)0x000000FF); nico@210: 00557 return 0xFF; nico@210: 00558 } nico@210: 00559 if (pMappedAppObject == variable) { // Variable found ! nico@210: 00560 MSG_WAR(0x3963, "Variable to send found at index : ", nico@210: 00561 (*pMappingParameter) >> 16); nico@210: 00562 MSG_WAR(0x3964, " subIndex : ", nico@210: 00563 ((*pMappingParameter) >> 8 ) & 0x000000FF); nico@210: 00564 buildPDO(d, 0x1800 + ind); nico@210: 00566 pwCobId = d->objdict[offsetObjdictPrm].pSubindex[1].pObject; nico@210: 00567 PDOmGR( d, *pwCobId ); nico@210: 00568 return 0; nico@210: 00569 } nico@210: 00570 numMap++; nico@210: 00571 } nico@210: 00572 ind++; nico@210: 00573 offsetObjdict++; nico@210: 00574 offsetObjdictPrm++; nico@210: 00575 } nico@210: 00577 MSG_WAR(0x2965, "Variable not found in a PDO to send on event", 0); nico@210: 00578 return 0xFF; nico@210: 00579 nico@210: 00580 } nico@210: 00581 #endif nico@210: 00582 nico@210: 00583 nico@210: 00584 nico@210: