|         |      1 /* | 
|         |      2 * Copyright (c) 2007-2010 Sebastian Brannstrom, Lars Persson, EmbedDev AB | 
|         |      3 * | 
|         |      4 * All rights reserved. | 
|         |      5 * This component and the accompanying materials are made available | 
|         |      6 * under the terms of the License "Eclipse Public License v1.0" | 
|         |      7 * which accompanies this distribution, and is available | 
|         |      8 * at the URL "http://www.eclipse.org/legal/epl-v10.html". | 
|         |      9 * | 
|         |     10 * Initial Contributors: | 
|         |     11 * EmbedDev AB - initial contribution. | 
|         |     12 * | 
|         |     13 * Contributors: | 
|         |     14 * | 
|         |     15 * Description: | 
|         |     16 * | 
|         |     17 */ | 
|         |     18  | 
|         |     19 // dbg_dp.h | 
|         |     20 // debug printouts | 
|         |     21  | 
|         |     22 /************************************************* | 
|         |     23  | 
|         |     24     USAGE | 
|         |     25     DP("Hi there"); | 
|         |     26     DP1("My name is %S", &name); | 
|         |     27     DPV1("My detailed info is %S", &detailedInfo); | 
|         |     28     DP_MSG(aMsg); | 
|         |     29     DP_MSG_COMPL(aMsg, r); | 
|         |     30     DP_EXC(aType); | 
|         |     31  | 
|         |     32     CUSTOMISATION | 
|         |     33     With SUPPORT_DP_CLIENT_SERVER_V2 defined, a | 
|         |     34     proper opcode type (default TOpcode) needs to | 
|         |     35     be specified. | 
|         |     36  | 
|         |     37     NOTE | 
|         |     38     This file may be included by many components | 
|         |     39     within one application and defining something | 
|         |     40     here will affect all such components. In such | 
|         |     41     cases it might be better to state a MACRO in | 
|         |     42     the intended component's MMP file. | 
|         |     43  | 
|         |     44 **************************************************/ | 
|         |     45  | 
|         |     46 #ifndef ___DBG_DP_H | 
|         |     47 #define ___DBG_DP_H | 
|         |     48  | 
|         |     49 // This file may be included butThese defines may be individual | 
|         |     50  | 
|         |     51 //#if defined (_DEBUG) && (__WINS__) | 
|         |     52 //#if defined _DEBUG | 
|         |     53 #   define SUPPORT_DP_STANDARD | 
|         |     54 #   define SUPPORT_DP_FILE | 
|         |     55 //#endif | 
|         |     56  | 
|         |     57 // #define SUPPORT_RDEBUG_PRINT | 
|         |     58 // #define SUPPORT_DP_VERBOSE | 
|         |     59 // #define SUPPORT_DP_THREAD_NAME | 
|         |     60 // #define SUPPORT_DP_CLIENT_SERVER_V2 | 
|         |     61 // #define SUPPORT_DP_EXCEPTION | 
|         |     62 // #define SUPPORT_DP_COMMDB | 
|         |     63  | 
|         |     64 // ------------------------------------------------- no need to modify | 
|         |     65  | 
|         |     66 #if defined (SUPPORT_RDEBUG_PRINT)\ | 
|         |     67  || defined (SUPPORT_DP_VERBOSE)\ | 
|         |     68  || defined(SUPPORT_DP_CLIENT_SERVER_V2)\ | 
|         |     69  || defined(SUPPORT_DP_EXCEPTION) | 
|         |     70 #   define SUPPORT_DP_STANDARD | 
|         |     71 #endif | 
|         |     72  | 
|         |     73 #if defined(SUPPORT_RDEBUG_PRINT) | 
|         |     74 #   include <e32svr.h> // RDebug | 
|         |     75 #endif | 
|         |     76  | 
|         |     77 #if defined(SUPPORT_DP_FILE) | 
|         |     78 #   include <flogger.h> | 
|         |     79 #endif | 
|         |     80  | 
|         |     81 #if defined(SUPPORT_DP_CLIENT_SERVER_V2) | 
|         |     82 #   include "dbg_cmn.h" // TOpcode | 
|         |     83 #endif | 
|         |     84  | 
|         |     85 #if defined(SUPPORT_DP_COMMDB) | 
|         |     86 #   include <commdbconnpref.h> // TCommDbConnPref | 
|         |     87 #endif | 
|         |     88  | 
|         |     89 namespace Dbg | 
|         |     90 { | 
|         |     91  | 
|         |     92 // ------------------------------------------------- file output | 
|         |     93 #ifdef SUPPORT_DP_FILE | 
|         |     94 _LIT(KLogDir, "podcatcher"); | 
|         |     95 _LIT(KLogFile, "debug.log"); | 
|         |     96 #   define DPF(a); RFileLogger::WriteFormat(Dbg::KLogDir, Dbg::KLogFile, EFileLoggingModeAppend, _L("%S %s"), &s, L##a); | 
|         |     97 #   define DPF1(a,b); RFileLogger::WriteFormat(Dbg::KLogDir, Dbg::KLogFile, EFileLoggingModeAppend, _L("%S " L##a), &s, b); | 
|         |     98 #   define DPF2(a,b,c); RFileLogger::WriteFormat(Dbg::KLogDir, Dbg::KLogFile, EFileLoggingModeAppend, _L("%S " L##a), &s, b,c); | 
|         |     99 #   define DPF3(a,b,c,d); RFileLogger::WriteFormat(Dbg::KLogDir, Dbg::KLogFile, EFileLoggingModeAppend, _L("%S " L##a), &s, b,c,d); | 
|         |    100 #   define DPF4(a,b,c,d,e); RFileLogger::WriteFormat(Dbg::KLogDir, Dbg::KLogFile, EFileLoggingModeAppend, _L("%S " L##a), &s, b,c,d,e); | 
|         |    101 #   define DPF5(a,b,c,d,e,f); RFileLogger::WriteFormat(Dbg::KLogDir, Dbg::KLogFile, EFileLoggingModeAppend, _L("%S " L##a), &s, b,c,d,e,f); | 
|         |    102 #   define DPF6(a,b,c,d,e,f,g); RFileLogger::WriteFormat(Dbg::KLogDir, Dbg::KLogFile, EFileLoggingModeAppend, _L("%S " L##a), &s, b, c, d,e,f,g); | 
|         |    103 #	define HEXDUMP(aHeader, aMargin, aPtr, aLen); RFileLogger::HexDump(Dbg::KLogDir, Dbg::KLogFile, EFileLoggingModeAppend, aHeader, aMargin, aPtr, aLen); | 
|         |    104 #   define DPDT(dt); RFileLogger::WriteFormat(Dbg::KLogDir, Dbg::KLogFile, EFileLoggingModeAppend, _L("DateTime: %d-%d-%d %d:%d:%d "), dt.Year(), dt.Month()+1, dt.Day()+1, dt.Hour(), dt.Minute(), dt.Second() ); | 
|         |    105  | 
|         |    106 #else | 
|         |    107 #   define DPF(a); | 
|         |    108 #   define DPF1(a,b); | 
|         |    109 #   define DPF2(a,b,c); | 
|         |    110 #   define DPF3(a,b,c,d); | 
|         |    111 #   define DPF4(a,b,c,d,e); | 
|         |    112 #   define DPF5(a,b,c,d,e,f); | 
|         |    113 #   define DPF6(a,b,c,d,e,f,g); | 
|         |    114 #	define HEXDUMP(aHeader, aMargin, aPtr, aLen); | 
|         |    115 #   define DPDT(dt);  | 
|         |    116 #endif | 
|         |    117 // ------------------------------------------------- standard debugprint | 
|         |    118 #ifdef SUPPORT_DP_STANDARD | 
|         |    119  | 
|         |    120 inline void FormatThreadName(TFullName& aName) | 
|         |    121 { | 
|         |    122     const TChar KLeftBracket('['); | 
|         |    123     const TChar KScope(':'); | 
|         |    124     TInt a = aName.LocateReverse(KLeftBracket); | 
|         |    125     if (a==KErrNotFound) | 
|         |    126         { return; } | 
|         |    127     TInt b = aName.Locate(KScope); | 
|         |    128     if (b==KErrNotFound || b<a) | 
|         |    129         { return; } | 
|         |    130     aName.Delete(a,b-a); | 
|         |    131 } | 
|         |    132  | 
|         |    133 #ifdef SUPPORT_RDEBUG_PRINT | 
|         |    134 #   define DP(a);\ | 
|         |    135     {\ | 
|         |    136         TFullName s = RThread().FullName();\ | 
|         |    137         Dbg::FormatThreadName(s);\ | 
|         |    138         RDebug::Print(_L("%S %s"), &s, L##a);\ | 
|         |    139         DPF(a);\ | 
|         |    140     } | 
|         |    141 #   define DP1(a,b);\ | 
|         |    142     {\ | 
|         |    143         TFullName s = RThread().FullName();\ | 
|         |    144         Dbg::FormatThreadName(s);\ | 
|         |    145         RDebug::Print(_L("%S " L##a), &s, b);\ | 
|         |    146         DPF1(a,b);\ | 
|         |    147     } | 
|         |    148 #   define DP2(a,b,c);\ | 
|         |    149     {\ | 
|         |    150         TFullName s = RThread().FullName();\ | 
|         |    151         Dbg::FormatThreadName(s);\ | 
|         |    152         RDebug::Print(_L("%S " L##a), &s, b,c);\ | 
|         |    153         DPF2(a,b,c);\ | 
|         |    154     } | 
|         |    155 #   define DP3(a,b,c,d);\ | 
|         |    156     {\ | 
|         |    157         TFullName s = RThread().FullName();\ | 
|         |    158         Dbg::FormatThreadName(s);\ | 
|         |    159         RDebug::Print(_L("%S " L##a), &s, b,c,d);\ | 
|         |    160         DPF3(a,b,c,d);\ | 
|         |    161     } | 
|         |    162 #   define DP4(a,b,c,d,e);\ | 
|         |    163     {\ | 
|         |    164         TFullName s = RThread().FullName();\ | 
|         |    165         Dbg::FormatThreadName(s);\ | 
|         |    166         RDebug::Print(_L("%S " L##a), &s, b,c,d,e);\ | 
|         |    167         DPF4(a,b,c,d,e);\ | 
|         |    168     } | 
|         |    169 #   define DP5(a,b,c,d,e,f);\ | 
|         |    170     {\ | 
|         |    171         TFullName s = RThread().FullName();\ | 
|         |    172         Dbg::FormatThreadName(s);\ | 
|         |    173         RDebug::Print(_L("%S " L##a), &s, b,c,d,e,f);\ | 
|         |    174         DPF5(a,b,c,d,e,f);\ | 
|         |    175     } | 
|         |    176 #   define DP6(a,b,c,d,e,f,g);\ | 
|         |    177     {\ | 
|         |    178         TFullName s = RThread().FullName();\ | 
|         |    179         Dbg::FormatThreadName(s);\ | 
|         |    180         RDebug::Print(_L("%S " L##a), &s, b,c,d,e,f,g);\ | 
|         |    181         DPF6(a,b,c,d,e,f,g);\ | 
|         |    182     } | 
|         |    183 #else	//SUPPORT_RDEBUG_PRINT | 
|         |    184 #   define DP(a);\ | 
|         |    185     {\ | 
|         |    186         TFullName s = RThread().FullName();\ | 
|         |    187         Dbg::FormatThreadName(s);\ | 
|         |    188         DPF(a);\ | 
|         |    189     } | 
|         |    190 #   define DP1(a,b);\ | 
|         |    191     {\ | 
|         |    192         TFullName s = RThread().FullName();\ | 
|         |    193         Dbg::FormatThreadName(s);\ | 
|         |    194         DPF1(a,b);\ | 
|         |    195     } | 
|         |    196 #   define DP2(a,b,c);\ | 
|         |    197     {\ | 
|         |    198         TFullName s = RThread().FullName();\ | 
|         |    199         Dbg::FormatThreadName(s);\ | 
|         |    200         DPF2(a,b,c);\ | 
|         |    201     } | 
|         |    202 #   define DP3(a,b,c,d);\ | 
|         |    203     {\ | 
|         |    204         TFullName s = RThread().FullName();\ | 
|         |    205         Dbg::FormatThreadName(s);\ | 
|         |    206         DPF3(a,b,c,d);\ | 
|         |    207     } | 
|         |    208 #   define DP4(a,b,c,d,e);\ | 
|         |    209     {\ | 
|         |    210         TFullName s = RThread().FullName();\ | 
|         |    211         Dbg::FormatThreadName(s);\ | 
|         |    212         DPF4(a,b,c,d,e);\ | 
|         |    213     } | 
|         |    214 #   define DP5(a,b,c,d,e,f);\ | 
|         |    215     {\ | 
|         |    216         TFullName s = RThread().FullName();\ | 
|         |    217         Dbg::FormatThreadName(s);\ | 
|         |    218         DPF5(a,b,c,d,e,f);\ | 
|         |    219     } | 
|         |    220 #   define DP6(a,b,c,d,e,f,g);\ | 
|         |    221     {\ | 
|         |    222         TFullName s = RThread().FullName();\ | 
|         |    223         Dbg::FormatThreadName(s);\ | 
|         |    224         DPF6(a,b,c,d,e,f,g);\ | 
|         |    225     } | 
|         |    226 #endif	//SUPPORT_RDEBUG_PRINT | 
|         |    227 #   define ASSERT_DP(a, b); {if(!(a)){DP(b);}} | 
|         |    228 #   define ASSERT_DP1(a,b,c); {if(!(a)){DP1(b,c);}} | 
|         |    229 #   define ASSERT_DP2(a,b,c,d); {if(!(a)){DP2(b,c,d);}} | 
|         |    230 #   define ASSERT_DP3(a,b,c,d,e); {if(!(a)){DP3(b,c,d,e);}} | 
|         |    231 #   define ASSERT_DP4(a,b,c,d,e,f); {if(!(a)){DP4(b,c,d,e,f);}} | 
|         |    232 #   define ASSERT_DP5(a,b,c,d,e,f,g); {if(!(a)){DP5(b,c,d,e,f,g);}} | 
|         |    233 #   define ASSERT_DP6(a,b,c,d,e,f,g,h); {if(!(a)){DP6(b,c,d,e,f,g,h);}} | 
|         |    234 // @brief stuff to get enum strings from enums | 
|         |    235 #   define ENUM_CASE(n,c)\ | 
|         |    236         case c: { _LIT(KTxt##c, #c); n.Set(KTxt##c); break; } | 
|         |    237 #   define DEFAULT(n)\ | 
|         |    238         default: { _LIT(KTxtUnknown, "Unknown"); n.Set(KTxtUnknown); break; } | 
|         |    239 #else | 
|         |    240 #   define DP(a); | 
|         |    241 #   define DP1(a,b);; | 
|         |    242 #   define DP2(a,b,c); | 
|         |    243 #   define DP3(a,b,c,d); | 
|         |    244 #   define DP4(a,b,c,d,e); | 
|         |    245 #   define DP5(a,b,c,d,e,f); | 
|         |    246 #   define DP6(a,b,c,d,e,f,g); | 
|         |    247 #   define ASSERT_DP(a, b); | 
|         |    248 #   define ASSERT_DP1(a,b,c); | 
|         |    249 #   define ASSERT_DP2(a,b,c,d); | 
|         |    250 #   define ASSERT_DP3(a,b,c,d,e); | 
|         |    251 #   define ASSERT_DP4(a,b,c,d,e,f); | 
|         |    252 #   define ASSERT_DP5(a,b,c,d,e,f,g); | 
|         |    253 #   define ASSERT_DP6(a,b,c,d,e,f,g,h); | 
|         |    254 #   define ENUM_CASE(n,c) | 
|         |    255 #   define DEFAULT(n) | 
|         |    256 #endif | 
|         |    257 // ------------------------------------------------- detailed debugprint | 
|         |    258 #ifdef SUPPORT_DP_VERBOSE | 
|         |    259 #   define DPV(a); { DP(a); } | 
|         |    260 #   define DPV1(a,b); { DP1(a,b); } | 
|         |    261 #   define DPV2(a,b,c); { DP2(a,b,c); } | 
|         |    262 #   define DPV3(a,b,c,d); { DP3(a,b,c,d); } | 
|         |    263 #   define DPV4(a,b,c,d,e); { DP4(a,b,c,d,e); } | 
|         |    264 #   define DPV5(a,b,c,d,e,f); { DP5(a,b,c,d,e,f); } | 
|         |    265 #   define DPV6(a,b,c,d,e,f,g); { DP6(a,b,c,d,e,f,g); } | 
|         |    266 #	define DPDTV(dt); { DPDT(dt); } | 
|         |    267 #else | 
|         |    268 #   define DPV(a); | 
|         |    269 #   define DPV1(a,b); | 
|         |    270 #   define DPV2(a,b,c); | 
|         |    271 #   define DPV3(a,b,c,d); | 
|         |    272 #   define DPV4(a,b,c,d,e); | 
|         |    273 #   define DPV5(a,b,c,d,e,f); | 
|         |    274 #   define DPV6(a,b,c,d,e,f,g); | 
|         |    275 #	define DPDTV(dt); | 
|         |    276 #endif | 
|         |    277 // ------------------------------------------------- client/server V2 | 
|         |    278 #ifdef SUPPORT_DP_CLIENT_SERVER_V2 | 
|         |    279  | 
|         |    280 // @brief Get client thread name from a message | 
|         |    281 static void GetClientName(const RMessage2& aMsg, TFullName& aName) | 
|         |    282 { | 
|         |    283     RThread thread; | 
|         |    284     aMsg.Client(thread); | 
|         |    285     aName = thread.FullName(); | 
|         |    286     Dbg::FormatThreadName(aName); | 
|         |    287 } | 
|         |    288  | 
|         |    289 // @brief Get server opcode from any message | 
|         |    290 static TOpcode GetServerOpcode(const RMessage2& aMsg) | 
|         |    291 { | 
|         |    292     return (TOpcode)aMsg.Function(); | 
|         |    293 } | 
|         |    294  | 
|         |    295 // @brief Get server opcode name from a server opcode | 
|         |    296 static TPtrC GetServerOpcodeName(TOpcode aOpcode) | 
|         |    297 { | 
|         |    298     TPtrC name; | 
|         |    299     switch(aOpcode) | 
|         |    300     { | 
|         |    301         // ENUM_CASE(name, EOpcodeOne); | 
|         |    302         // ENUM_CASE(name, EOpcodeTwo); | 
|         |    303         DEFAULT(name); | 
|         |    304     } | 
|         |    305     return name; | 
|         |    306 } | 
|         |    307  | 
|         |    308 // @brief Print generic message. | 
|         |    309 inline void PrintMsg(const RMessage2& aMsg) | 
|         |    310 { | 
|         |    311     TFullName threadName; | 
|         |    312     GetClientName(aMsg, threadName); | 
|         |    313     TOpcode sOpcode = GetServerOpcode(aMsg); | 
|         |    314     TPtrC sOpcodeName = GetServerOpcodeName(sOpcode); | 
|         |    315     DP3("? %S %S(%d)", &threadName, &sOpcodeName, sOpcode); | 
|         |    316 } | 
|         |    317  | 
|         |    318 // @brief Print generic message completion. | 
|         |    319 inline void PrintMsgCompl(const RMessage2& aMsg, TInt aErr) | 
|         |    320 { | 
|         |    321     TFullName threadName; | 
|         |    322     GetClientName(aMsg, threadName); | 
|         |    323     TOpcode sOpcode = GetServerOpcode(aMsg); | 
|         |    324     TPtrC sOpcodeName = GetServerOpcodeName(sOpcode); | 
|         |    325     DP4("! %S %S(%d) r=%d", &threadName, &sOpcodeName, sOpcode, aErr); | 
|         |    326 } | 
|         |    327  | 
|         |    328 // m= message, r=error | 
|         |    329 #   define DP_MSG(m); PrintMsg(m); | 
|         |    330 #   define DP_MSG_COMPL(m,r); PrintMsgCompl(m,r); | 
|         |    331 #else | 
|         |    332 #   define DP_MSG(m); | 
|         |    333 #   define DP_MSG_COMPL(m,r); | 
|         |    334 #endif | 
|         |    335 // ------------------------------------------------- exception debugprint | 
|         |    336 #ifdef SUPPORT_DP_EXCEPTION | 
|         |    337  | 
|         |    338 // @brief Get an exception type | 
|         |    339 static TPtrC GetExcName(TExcType aType) | 
|         |    340 { | 
|         |    341     TPtrC name; | 
|         |    342     switch(aType) | 
|         |    343     { | 
|         |    344         ENUM_CASE(name, EExcGeneral); | 
|         |    345         ENUM_CASE(name, EExcIntegerDivideByZero); | 
|         |    346         ENUM_CASE(name, EExcSingleStep); | 
|         |    347         ENUM_CASE(name, EExcBreakPoint); | 
|         |    348         ENUM_CASE(name, EExcIntegerOverflow); | 
|         |    349         ENUM_CASE(name, EExcBoundsCheck); | 
|         |    350         ENUM_CASE(name, EExcInvalidOpCode); | 
|         |    351         ENUM_CASE(name, EExcDoubleFault); | 
|         |    352         ENUM_CASE(name, EExcStackFault); | 
|         |    353         ENUM_CASE(name, EExcAccessViolation); | 
|         |    354         ENUM_CASE(name, EExcPrivInstruction); | 
|         |    355         ENUM_CASE(name, EExcAlignment); | 
|         |    356         ENUM_CASE(name, EExcPageFault); | 
|         |    357         ENUM_CASE(name, EExcFloatDenormal); | 
|         |    358         ENUM_CASE(name, EExcFloatDivideByZero); | 
|         |    359         ENUM_CASE(name, EExcFloatInexactResult); | 
|         |    360         ENUM_CASE(name, EExcFloatInvalidOperation); | 
|         |    361         ENUM_CASE(name, EExcFloatOverflow); | 
|         |    362         ENUM_CASE(name, EExcFloatStackCheck); | 
|         |    363         ENUM_CASE(name, EExcFloatUnderflow); | 
|         |    364         ENUM_CASE(name, EExcAbort); | 
|         |    365         ENUM_CASE(name, EExcKill); | 
|         |    366         ENUM_CASE(name, EExcUserInterrupt); | 
|         |    367         ENUM_CASE(name, EExcDataAbort); | 
|         |    368         ENUM_CASE(name, EExcCodeAbort); | 
|         |    369         ENUM_CASE(name, EExcMaxNumber); | 
|         |    370         ENUM_CASE(name, EExcInvalidVector); | 
|         |    371         DEFAULT(name); | 
|         |    372     } | 
|         |    373     return name; | 
|         |    374 } | 
|         |    375  | 
|         |    376 // @brief Print exception info. | 
|         |    377 inline void PrintExc(TExcType aType) | 
|         |    378 { | 
|         |    379     TPtrC excName = GetExcName(aType); | 
|         |    380     DP2("### Exception %S(%d) ###", &excName, aType); | 
|         |    381 } | 
|         |    382  | 
|         |    383 #   define DP_EXC(t); PrintExc(t); | 
|         |    384 #else | 
|         |    385 #   define DP_EXC(t); | 
|         |    386 #endif | 
|         |    387 // -------------------------------------------------  | 
|         |    388 #ifdef SUPPORT_DP_COMMDB | 
|         |    389  | 
|         |    390 inline void LogIap(const TDesC* aName, const TCommDbConnPref& aPref) | 
|         |    391 { | 
|         |    392     TUint32 iapId=aPref.IapId(); | 
|         |    393     TUint32 netId=aPref.NetId(); | 
|         |    394     TCommDbDialogPref dlgPref=aPref.DialogPreference(); | 
|         |    395     TCommDbConnectionDirection dir=aPref.Direction(); | 
|         |    396     TUint32 bearerSet=aPref.BearerSet(); | 
|         |    397     if(aName==0) | 
|         |    398     { | 
|         |    399         UI_FLOG(Log::Printf( | 
|         |    400             _L("iapId=%u, netId=%u, dlgPref=%d, dir=%d, bearerSet=0x%02x"), | 
|         |    401             iapId, netId, dlgPref, dir, bearerSet)); | 
|         |    402     } | 
|         |    403     else | 
|         |    404     { | 
|         |    405         UI_FLOG(Log::Printf( | 
|         |    406             _L("\"%S\", iapId=%u, netId=%u, dlgPref=%d, dir=%d, bearerSet=0x%02x"), | 
|         |    407             aName, iapId, netId, dlgPref, dir, bearerSet)); | 
|         |    408     } | 
|         |    409 } | 
|         |    410  | 
|         |    411 #   define DP_COMMDBCONNPREF(a,b); LogIap(a,b); | 
|         |    412 #else | 
|         |    413 #   define DP_COMMDBCONNPREF(a,b); | 
|         |    414 #endif | 
|         |    415 // -------------------------------------------------  | 
|         |    416  | 
|         |    417 } | 
|         |    418 #endif //___DBG_DP_H | 
|         |    419  |