51 /* |
51 /* |
52 * Note1: This file uses AT command parsing based on heuristics. |
52 * Note1: This file uses AT command parsing based on heuristics. |
53 * Refer to test specification if planning to change the heuristic. |
53 * Refer to test specification if planning to change the heuristic. |
54 * Note2: Input buffer management (ExtractLineFromInputBuffer()) can be tested |
54 * Note2: Input buffer management (ExtractLineFromInputBuffer()) can be tested |
55 * with non-line based terminals such as HyperTerminal or Realterm. |
55 * with non-line based terminals such as HyperTerminal or Realterm. |
|
56 * Note3: If there is a need to handle commands with random data, the extended |
|
57 * command checking can interfere with the character set of this random data. |
|
58 * Best way to handle this random data is to create a handler for these commands |
|
59 * which skips the valid "not to be parsed" data or use quotes. For these cases |
|
60 * the CDunAtSpecialCmdHandler could be extended. |
56 */ |
61 */ |
57 |
62 |
58 #include "DunAtCmdHandler.h" |
63 #include "DunAtCmdHandler.h" |
59 #include "DunAtUrcHandler.h" |
64 #include "DunAtUrcHandler.h" |
60 #include "DunDownstream.h" |
65 #include "DunDownstream.h" |
976 TInt inputLength = iInput->Length(); |
981 TInt inputLength = iInput->Length(); |
977 TInt foundIndex = inputLength; |
982 TInt foundIndex = inputLength; |
978 for ( TInt i=aStartIndex; i<inputLength; i++ ) |
983 for ( TInt i=aStartIndex; i<inputLength; i++ ) |
979 { |
984 { |
980 TChar character = (*iInput)[i]; |
985 TChar character = (*iInput)[i]; |
981 if ( !IsDelimiterCharacter(character) ) |
986 if ( !IsDelimiterCharacter(character,ETrue,ETrue) ) |
982 { |
987 { |
983 foundIndex = i; |
988 foundIndex = i; |
984 break; |
989 break; |
985 } |
990 } |
986 } |
991 } |
1160 if ( !aPeek ) |
1165 if ( !aPeek ) |
1161 { |
1166 { |
1162 iDecodeInfo.iCmdsHandled++; |
1167 iDecodeInfo.iCmdsHandled++; |
1163 FTRACE(FPrint( _L("CDunAtCmdHandler::ExtractNextSubCommand() (handled=%d)"), iDecodeInfo.iCmdsHandled )); |
1168 FTRACE(FPrint( _L("CDunAtCmdHandler::ExtractNextSubCommand() (handled=%d)"), iDecodeInfo.iCmdsHandled )); |
1164 } |
1169 } |
|
1170 FTRACE(FPrint( _L("CDunAtCmdPusher::ExtractNextSubCommand() extracted:") )); |
|
1171 FTRACE(FPrintRaw(iParseInfo.iSendBuffer) ); |
1165 FTRACE(FPrint( _L("CDunAtCmdHandler::ExtractNextSubCommand() complete") )); |
1172 FTRACE(FPrint( _L("CDunAtCmdHandler::ExtractNextSubCommand() complete") )); |
1166 return ETrue; |
1173 return ETrue; |
1167 } |
1174 } |
1168 |
1175 |
1169 // --------------------------------------------------------------------------- |
1176 // --------------------------------------------------------------------------- |
1177 TInt foundIndex = KErrNotFound; |
1184 TInt foundIndex = KErrNotFound; |
1178 TInt lineLength = iLineBuffer.Length(); |
1185 TInt lineLength = iLineBuffer.Length(); |
1179 for ( i=iDecodeInfo.iDecodeIndex; i<lineLength; i++ ) |
1186 for ( i=iDecodeInfo.iDecodeIndex; i<lineLength; i++ ) |
1180 { |
1187 { |
1181 TChar character = iLineBuffer[i]; |
1188 TChar character = iLineBuffer[i]; |
1182 if ( !IsDelimiterCharacter(character) ) |
1189 if ( !IsDelimiterCharacter(character,ETrue,ETrue) ) |
1183 { |
1190 { |
1184 foundIndex = i; |
1191 foundIndex = i; |
1185 break; |
1192 break; |
1186 } |
1193 } |
1187 } |
1194 } |
1224 |
1231 |
1225 // --------------------------------------------------------------------------- |
1232 // --------------------------------------------------------------------------- |
1226 // Checks if character is delimiter character |
1233 // Checks if character is delimiter character |
1227 // --------------------------------------------------------------------------- |
1234 // --------------------------------------------------------------------------- |
1228 // |
1235 // |
1229 TBool CDunAtCmdHandler::IsDelimiterCharacter( TChar aCharacter ) |
1236 TBool CDunAtCmdHandler::IsDelimiterCharacter( TChar aCharacter, |
|
1237 TBool aBasic, |
|
1238 TBool aExtended ) |
1230 { |
1239 { |
1231 FTRACE(FPrint( _L("CDunAtCmdHandler::IsDelimiterCharacter()") )); |
1240 FTRACE(FPrint( _L("CDunAtCmdHandler::IsDelimiterCharacter()") )); |
1232 if ( aCharacter.IsSpace() || aCharacter==';' || aCharacter==0x00 ) |
1241 if ( aBasic && ( aCharacter.IsSpace()||aCharacter==0x00) ) |
1233 { |
1242 { |
1234 FTRACE(FPrint( _L("CDunAtCmdHandler::IsDelimiterCharacter() complete") )); |
1243 FTRACE(FPrint( _L("CDunAtCmdHandler::IsDelimiterCharacter() complete") )); |
|
1244 return ETrue; |
|
1245 } |
|
1246 if ( aExtended && aCharacter == ';' ) |
|
1247 { |
|
1248 FTRACE(FPrint( _L("CDunAtCmdHandler::IsDelimiterCharacter() (extended) complete") )); |
1235 return ETrue; |
1249 return ETrue; |
1236 } |
1250 } |
1237 FTRACE(FPrint( _L("CDunAtCmdHandler::IsDelimiterCharacter() (not delimiter) complete") )); |
1251 FTRACE(FPrint( _L("CDunAtCmdHandler::IsDelimiterCharacter() (not delimiter) complete") )); |
1238 return EFalse; |
1252 return EFalse; |
1239 } |
1253 } |
1243 // --------------------------------------------------------------------------- |
1257 // --------------------------------------------------------------------------- |
1244 // |
1258 // |
1245 TBool CDunAtCmdHandler::IsExtendedCharacter( TChar aCharacter ) |
1259 TBool CDunAtCmdHandler::IsExtendedCharacter( TChar aCharacter ) |
1246 { |
1260 { |
1247 FTRACE(FPrint( _L("CDunAtCmdHandler::IsExtendedCharacter()") )); |
1261 FTRACE(FPrint( _L("CDunAtCmdHandler::IsExtendedCharacter()") )); |
|
1262 // Extended characters supported by this function (parser understands these) |
|
1263 // '+': Universal; mentioned in 3GPP TS 27.007, 3GPP TS 27.005, ITU-T V.250 |
|
1264 // '&': Mentioned in ITU-T V.250 and in some "de facto" commands |
|
1265 // '%': Used by some old Hayes modems, left just in case |
|
1266 // '\': Used by some old Hayes modems, left just in case |
|
1267 // '*': Used by some old Hayes modems, AT&T and others |
|
1268 // '#': Used by some old Hayes modems, left just in case |
|
1269 // '$': Used by AT&T and Qualcomm |
|
1270 // '^': Used by China Mobile |
|
1271 // [please maintain this list here for quick reference] |
1248 if ( aCharacter=='+' || aCharacter=='&' || aCharacter=='%' || |
1272 if ( aCharacter=='+' || aCharacter=='&' || aCharacter=='%' || |
1249 aCharacter=='\\' || aCharacter=='*' || aCharacter=='#' || |
1273 aCharacter=='\\' || aCharacter=='*' || aCharacter=='#' || |
1250 aCharacter=='$' || aCharacter=='^' ) |
1274 aCharacter=='$' || aCharacter=='^' ) |
1251 { |
1275 { |
1252 FTRACE(FPrint( _L("CDunAtCmdHandler::IsExtendedCharacter() complete") )); |
1276 FTRACE(FPrint( _L("CDunAtCmdHandler::IsExtendedCharacter() complete") )); |
1375 SaveNotFoundCharDecodeState(); |
1399 SaveNotFoundCharDecodeState(); |
1376 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommandQuotes() (in quotes) complete") )); |
1400 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommandQuotes() (in quotes) complete") )); |
1377 return ETrue; |
1401 return ETrue; |
1378 } |
1402 } |
1379 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommandQuotes() (not found) complete") )); |
1403 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommandQuotes() (not found) complete") )); |
|
1404 return EFalse; |
|
1405 } |
|
1406 |
|
1407 // --------------------------------------------------------------------------- |
|
1408 // Check if in basic command delimiter skip zone |
|
1409 // --------------------------------------------------------------------------- |
|
1410 // |
|
1411 TBool CDunAtCmdHandler::IsBasicDelimiterSkipZone( TChar aCharacter, |
|
1412 TInt& aEndIndex ) |
|
1413 { |
|
1414 FTRACE(FPrint( _L("CDunAtCmdHandler::IsBasicDelimiterSkipZone()") )); |
|
1415 if ( !IsDelimiterCharacter(aCharacter,ETrue,EFalse) ) |
|
1416 { |
|
1417 FTRACE(FPrint( _L("CDunAtCmdHandler::IsBasicDelimiterSkipZone() complete") )); |
|
1418 return EFalse; |
|
1419 } |
|
1420 // Check the case after '=' |
|
1421 if ( iDecodeInfo.iAssignFound ) |
|
1422 { |
|
1423 FTRACE(FPrint( _L("CDunAtCmdHandler::IsBasicDelimiterSkipZone() (after =) complete") )); |
|
1424 return ETrue; |
|
1425 } |
|
1426 // Check the case before '=' |
|
1427 TInt peekIndex = aEndIndex + 1; |
|
1428 TInt lineLength = iLineBuffer.Length(); |
|
1429 for ( ; peekIndex<lineLength; peekIndex++ ) |
|
1430 { |
|
1431 TChar peekCharacter = iLineBuffer[peekIndex]; |
|
1432 if ( peekCharacter=='?' || peekCharacter=='=' ) |
|
1433 { |
|
1434 aEndIndex = peekIndex; |
|
1435 FTRACE(FPrint( _L("CDunAtCmdHandler::IsBasicDelimiterSkipZone() (? or =) complete") )); |
|
1436 return ETrue; |
|
1437 } |
|
1438 if ( !IsDelimiterCharacter(peekCharacter,ETrue,EFalse) ) |
|
1439 { |
|
1440 break; |
|
1441 } |
|
1442 } |
|
1443 FTRACE(FPrint( _L("CDunAtCmdHandler::IsBasicDelimiterSkipZone() complete") )); |
1380 return EFalse; |
1444 return EFalse; |
1381 } |
1445 } |
1382 |
1446 |
1383 // --------------------------------------------------------------------------- |
1447 // --------------------------------------------------------------------------- |
1384 // Check if in next subcommand's extended border |
1448 // Check if in next subcommand's extended border |
1434 if ( iDecodeInfo.iAssignFound && !iDecodeInfo.iInQuotes ) |
1498 if ( iDecodeInfo.iAssignFound && !iDecodeInfo.iInQuotes ) |
1435 { |
1499 { |
1436 // Check the special case when assigning a number with "basic" command |
1500 // Check the special case when assigning a number with "basic" command |
1437 // and there is no delimiter after it. In this case <Numeric>|<Alpha> |
1501 // and there is no delimiter after it. In this case <Numeric>|<Alpha> |
1438 // border must be detected but only for a "basic" command, not for |
1502 // border must be detected but only for a "basic" command, not for |
1439 // extended. |
1503 // extended. This type of case is in active use in initialization |
|
1504 // strings where "ATS7=60L1M1X3" is one example |
1440 if ( iDecodeInfo.iExtendedIndex<0 && iDecodeInfo.iPrevExists && |
1505 if ( iDecodeInfo.iExtendedIndex<0 && iDecodeInfo.iPrevExists && |
1441 iDecodeInfo.iPrevChar.IsDigit() && aCharacter.IsAlpha() ) |
1506 iDecodeInfo.iPrevChar.IsDigit() && aCharacter.IsAlpha() ) |
1442 { |
1507 { |
1443 aEndIndex--; |
1508 aEndIndex--; |
1444 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommandAlphaBorder() (N|A) complete") )); |
1509 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommandAlphaBorder() (N|A) complete") )); |
1495 { |
1560 { |
1496 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommand()") )); |
1561 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommand()") )); |
1497 TInt startIndex = iDecodeInfo.iDecodeIndex; |
1562 TInt startIndex = iDecodeInfo.iDecodeIndex; |
1498 aEndIndex = startIndex; |
1563 aEndIndex = startIndex; |
1499 TBool found = EFalse; |
1564 TBool found = EFalse; |
|
1565 TBool skipZone = EFalse; |
1500 TInt lineLength = iLineBuffer.Length(); |
1566 TInt lineLength = iLineBuffer.Length(); |
1501 iDecodeInfo.iAssignFound = EFalse; |
1567 iDecodeInfo.iAssignFound = EFalse; |
1502 iDecodeInfo.iInQuotes = EFalse; |
1568 iDecodeInfo.iInQuotes = EFalse; |
1503 iDecodeInfo.iExtendedIndex = KErrNotFound; |
1569 iDecodeInfo.iExtendedIndex = KErrNotFound; |
1504 SaveNotFoundCharDecodeState(); |
1570 SaveNotFoundCharDecodeState(); |
1505 iAtSpecialCmdHandler->ResetComparisonBuffer(); // just to be sure |
1571 iAtSpecialCmdHandler->ResetComparisonBuffer(); // just to be sure |
1506 for ( ; aEndIndex<lineLength; aEndIndex++ ) |
1572 for ( ; aEndIndex<lineLength; aEndIndex++ ) |
1507 { |
1573 { |
1508 TChar character = iLineBuffer[aEndIndex]; |
1574 TChar character = iLineBuffer[aEndIndex]; |
|
1575 // Skip '=', quotes and data in quotes |
1509 found = FindSubCommandQuotes( character, startIndex, aEndIndex ); |
1576 found = FindSubCommandQuotes( character, startIndex, aEndIndex ); |
1510 if ( found ) |
1577 if ( found ) |
1511 { |
1578 { |
1512 continue; |
1579 continue; |
1513 } |
1580 } |
|
1581 // Skip basic command delimiter in the following cases: |
|
1582 // "ATCOMMAND ?" |
|
1583 // "AT+COMMAND =" |
|
1584 // "AT+COMMAND=PARAM1, PARAM2" |
|
1585 skipZone = IsBasicDelimiterSkipZone( character, aEndIndex ); |
|
1586 if ( skipZone ) |
|
1587 { |
|
1588 continue; |
|
1589 } |
|
1590 // If '?', stop immediately |
1514 if ( character == '?' ) |
1591 if ( character == '?' ) |
1515 { |
1592 { |
1516 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommand() (?) complete") )); |
1593 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommand() (?) complete") )); |
1517 return KErrNone; |
1594 return KErrNone; |
1518 } |
1595 } |
1519 // The check below detects the following type of cases: |
1596 // The check below detects the following type of cases: |
1520 // ATCMD<delimiter> |
1597 // ATCMD<delimiter> |
1521 if ( IsDelimiterCharacter(character) ) |
1598 if ( IsDelimiterCharacter(character,ETrue,ETrue) ) |
1522 { |
1599 { |
1523 aEndIndex--; |
1600 aEndIndex--; |
1524 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommand() (delimiter) complete") )); |
1601 FTRACE(FPrint( _L("CDunAtCmdHandler::FindSubCommand() (delimiter) complete") )); |
1525 return KErrNone; |
1602 return KErrNone; |
1526 } |
1603 } |