diff --git a/docs/doxygen/portingCellularModule.dox b/docs/doxygen/portingCellularModule.dox
index 89360a6c..760ee9d9 100644
--- a/docs/doxygen/portingCellularModule.dox
+++ b/docs/doxygen/portingCellularModule.dox
@@ -167,8 +167,10 @@ They can be used to reduce porting effort.
@page cellular_module_urc_handler cellular_module_urc_handler
@brief Implement URC handler to handle URC event and call the corresponding callback function.
- @ref CellularTokenTable_t.pCellularUrcHandlerTable : URC handler table of @ref CellularAtParseTokenHandler_t
-- @ref CellularTokenTable_t.cellularPrefixToParserMapSize
-Example URC handler table.
+- @ref CellularTokenTable_t.cellularPrefixToParserMapSize : The size of the URC handler table
+
+
+Example URC handler table:
```
CellularAtParseTokenMap_t CellularUrcHandlerTable[] =
{
@@ -179,9 +181,44 @@ CellularAtParseTokenMap_t CellularUrcHandlerTable[] =
}
uint32_t CellularUrcHandlerTableSize = 4;
```
+
+There are two types of URC strings can be handled with this table:
+- URC with prefix
+This type of URC string is of the following format:
+> \\":"\
+The logic to check the URC prefix can be referenced in @ref Cellular_ATIsPrefixPresent
+Example of URC with prefix: "+CREG:2,0"
+In this example,
+URC_leading_char is "+"
+URC_prefix is "CREG"
+URC_payload is "2,0"
+The URC callback function, @ref CellularAtParseTokenHandler_t, will be called with
+ parameter pInputStr point to string URC_payload, "2,0" in this example.
+> The default prefix leading char can be referenced in this config @ref CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR.
+> The default valid prefix string chars can be referenced in this config @ref CELLULAR_CHECK_IS_PREFIX_CHAR.
+> Reference @subpage cellular_prefix_string_customize_config for more information.
+
+- URC without prefix
+This type of URC string is of fixed format.
+Example of URC without prefix : "NORMAL POWER DOWN"
+The URC callback function, @ref CellularAtParseTokenHandler_t, will be called with
+ parameter pInputStr point to URC string, "NORMAL POWER DOWN" in this example.
+
+
@image html cellular_URC_handler_implementation.png width=80%
*/
+/**
+@page cellular_prefix_string_customize_config Customization config for prefix string.
+@brief The config can be redefined in cellular_config.h to support different modem prefix string format.
+
+@section CELLULAR_CHECK_IS_PREFIX_CHAR
+@copydoc CELLULAR_CHECK_IS_PREFIX_CHAR
+
+@section CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR
+@copydoc CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR
+*/
+
/**
@paramstructs_group{cellular_common,Cellular_common}
@paramstructs_brief{cellular_common,cellular_common}
diff --git a/lexicon.txt b/lexicon.txt
index d86489b7..2ae54e15 100644
--- a/lexicon.txt
+++ b/lexicon.txt
@@ -293,6 +293,7 @@ firmwareversion
freertos
freertosconfig
fucntion
+fso
functionpointers
fw
gcc
@@ -468,6 +469,7 @@ parsetimezoneinfo
parseyearmonthdayincclkresponse
partialdata
partialdatarcvdlen
+passcomparestring
patbuf
patcmd
patcommandpayload
@@ -495,6 +497,7 @@ pcomminterface
pcomminterfacehandle
pcommintf
pcontext
+pcomparestring
pcurrentcmd
pcwriteto
pdata
@@ -529,6 +532,7 @@ phexdata
pinputbuf
pinputline
pinputptr
+pinputstr
pitm
pkio
pkt
@@ -751,6 +755,7 @@ simcardstate
simlockstate
sinr
sms
+smso
snprintf
socketclose
socketconnect
diff --git a/source/cellular_at_core.c b/source/cellular_at_core.c
index b1b62769..0b46504f 100644
--- a/source/cellular_at_core.c
+++ b/source/cellular_at_core.c
@@ -45,15 +45,6 @@
/*-----------------------------------------------------------*/
-#ifndef CELLULAR_CHECK_IS_PREFIX_CHAR
- #define CELLULAR_CHECK_IS_PREFIX_CHAR( inputChar ) \
- ( ( ( ( int32_t ) isalpha( ( ( int8_t ) ( inputChar ) ) ) ) == 0 ) && \
- ( ( ( int32_t ) isdigit( ( ( int8_t ) ( inputChar ) ) ) ) == 0 ) && \
- ( ( inputChar ) != '+' ) && ( ( inputChar ) != '_' ) )
-#endif
-
-/*-----------------------------------------------------------*/
-
/**
* @brief String validation results.
*/
@@ -136,6 +127,10 @@ CellularATError_t Cellular_ATIsPrefixPresent( const char * pString,
{
*pResult = false;
}
+ else if( !CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR( *pString ) )
+ {
+ *pResult = false;
+ }
else
{
/* There should be only '+', '_', characters or digit before seperator. */
diff --git a/source/cellular_pkthandler.c b/source/cellular_pkthandler.c
index 90f9a5c5..456b58af 100644
--- a/source/cellular_pkthandler.c
+++ b/source/cellular_pkthandler.c
@@ -133,20 +133,22 @@ static CellularPktStatus_t urcParseToken( CellularContext_t * pContext,
char * pInputLine )
{
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
+ bool inputWithPrefix = false;
/* pInputLine = "+" pTokenPtr + ":" + pSavePtr.
* if string not start with "+", then pTokenPtr = pSavePtr = pInputPtr. */
char * pSavePtr = pInputLine, * pTokenPtr = pInputLine;
-
LogDebug( ( "Next URC token to parse [%s]", pInputLine ) );
- /* First check for + at the beginning and advance to point to the next
- * byte. Use that string to pass to strtok and retrieve the token. Once the
- * token use is retrieved, get the function handler map and call that
- * function. */
- if( *pSavePtr == '+' )
+ /* Check if prefix exist in the input string. The pInputLine is checked in _processUrcPacket. */
+ ( void ) Cellular_ATIsPrefixPresent( pInputLine, &inputWithPrefix );
+
+ if( inputWithPrefix == true )
{
+ /* Cellular_ATIsPrefixPresent check the prefix string is valid and start with
+ * leading char. ":" is also checked in Cellular_ATIsPrefixPresent. Remove
+ * the leading char and split the string. */
pSavePtr++;
pTokenPtr = strtok_r( pSavePtr, ":", &pSavePtr );
@@ -156,6 +158,12 @@ static CellularPktStatus_t urcParseToken( CellularContext_t * pContext,
pktStatus = CELLULAR_PKT_STATUS_BAD_REQUEST;
}
}
+ else
+ {
+ /* This is the input without prefix case. Nothing need to be done for this case.
+ * There are some special cases. For example, "+URC" the string without ":" should
+ * be regarded as URC without prefix. */
+ }
if( pktStatus == CELLULAR_PKT_STATUS_OK )
{
diff --git a/source/include/cellular_config_defaults.h b/source/include/cellular_config_defaults.h
index 16cfb4ec..fd1d8cc8 100644
--- a/source/include/cellular_config_defaults.h
+++ b/source/include/cellular_config_defaults.h
@@ -401,6 +401,45 @@
#define CELLULAR_CONFIG_MAX_PREFIX_STRING_LENGTH ( 32U )
#endif
+/**
+ * @brief Macro to check prefix leading char.
+ *
+ * Cellular interface requires prefix string starts with "+". Some cellular modem
+ * uses different leading char. This macro can be defined in cellular_config.h to
+ * support different leading char.
+ *
+ * Default value (if undefined): '+'
+ *
+ * For example:
+ * > ^SMSO:(list of supporteds)
+ * The prefix string contains "^" which is not default leading char for prefix
+ * string. User can define this config to support this prefix string.
+ */
+#ifndef CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR
+ #define CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR( x ) ( ( x ) == '+' )
+#endif
+
+/**
+ * @brief Macro to check prefix chars.
+ *
+ * The macro to check prefix string contains valid char. Modem with different prefix
+ * strings can be supported with this config.
+ *
+ * Default value (if undefined): alphabet, digit, '+' and '_'
+ *
+ * For example:
+ * > +APP PDP: 0,ACTIVE
+ * The prefix string contains space which is not default valid char. User can define
+ * this config to support this prefix string.
+ */
+#ifndef CELLULAR_CHECK_IS_PREFIX_CHAR
+ #define CELLULAR_CHECK_IS_PREFIX_CHAR( inputChar ) \
+ ( ( ( ( int32_t ) isalpha( ( ( int8_t ) ( inputChar ) ) ) ) == 0 ) && \
+ ( ( ( int32_t ) isdigit( ( ( int8_t ) ( inputChar ) ) ) ) == 0 ) && \
+ ( ( inputChar ) != '_' ) && \
+ ( !( CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR( inputChar ) ) ) )
+#endif
+
/**
* @brief Macro that is called in the cellular library for logging "Error" level
* messages.
diff --git a/test/unit-test/cellular_at_core_utest.c b/test/unit-test/cellular_at_core_utest.c
index 9bcf37fd..7accfd06 100644
--- a/test/unit-test/cellular_at_core_utest.c
+++ b/test/unit-test/cellular_at_core_utest.c
@@ -167,6 +167,11 @@
*/
#define CELLULAR_SAMPLE_PREFIX_STRING_STAR_FIRST_INPUT "*CPIN:READY"
+/**
+ * @brief Cellular sample prefix string with invalid prefix char.
+ */
+#define CELLULAR_SAMPLE_PREFIX_STRING_INVALID_PREFIX_CHAR "+*CPIN:READY"
+
static int mallocAllocFail = 0;
/* ============================ UNITY FIXTURES ============================ */
@@ -1055,3 +1060,17 @@ void test_Cellular_ATIsPrefixPresent_Wrong_Prefix( void )
TEST_ASSERT_EQUAL( CELLULAR_AT_SUCCESS, cellularStatus );
TEST_ASSERT_EQUAL( false, Result );
}
+
+/**
+ * @brief Test the string with wrong prefix case for Cellular_ATIsPrefixPresent to return CELLULAR_AT_BAD_PARAMETER.
+ */
+void test_Cellular_ATIsPrefixPresent_Invalid_Prefix_Char( void )
+{
+ CellularATError_t cellularStatus = CELLULAR_AT_SUCCESS;
+ char pString[] = CELLULAR_SAMPLE_PREFIX_STRING_INVALID_PREFIX_CHAR;
+ bool Result;
+
+ cellularStatus = Cellular_ATIsPrefixPresent( pString, &Result );
+ TEST_ASSERT_EQUAL( CELLULAR_AT_SUCCESS, cellularStatus );
+ TEST_ASSERT_EQUAL( false, Result );
+}
diff --git a/test/unit-test/cellular_pkthandler_utest.c b/test/unit-test/cellular_pkthandler_utest.c
index 71af69dc..15072fef 100644
--- a/test/unit-test/cellular_pkthandler_utest.c
+++ b/test/unit-test/cellular_pkthandler_utest.c
@@ -52,6 +52,7 @@
#define CELLULAR_AT_MULTI_DATA_WO_PREFIX_STRING_RESP "+QIRD: 32\r123243154354364576587utrhfgdghfg"
#define CELLULAR_URC_TOKEN_STRING_INPUT "RDY"
#define CELLULAR_URC_TOKEN_STRING_INPUT_START_PLUS "+RDY"
+#define CELLULAR_URC_TOKEN_STRING_INPUT_WITH_PAYLOAD "+RDY:START"
#define CELLULAR_URC_TOKEN_STRING_GREATER_INPUT "RDYY"
#define CELLULAR_URC_TOKEN_STRING_SMALLER_INPUT "RD"
#define CELLULAR_PLUS_TOKEN_ONLY_STRING "+"
@@ -327,6 +328,38 @@ uint16_t MockvQueueDelete( QueueHandle_t queue )
return 1;
}
+CellularATError_t Cellular_ATIsPrefixPresent( const char * pString,
+ bool * pResult )
+{
+ CellularATError_t atStatus = CELLULAR_AT_SUCCESS;
+
+ TEST_ASSERT( pString != NULL );
+ TEST_ASSERT( pResult != NULL );
+
+ if( strcmp( pString, CELLULAR_AT_MULTI_DATA_WO_PREFIX_STRING_RESP ) == 0 )
+ {
+ *pResult = true;
+ }
+ else if( strcmp( pString, CELLULAR_PLUS_TOKEN_ONLY_STRING ) == 0 )
+ {
+ *pResult = true;
+ }
+ else if( strcmp( pString, CELLULAR_URC_TOKEN_STRING_INPUT_WITH_PAYLOAD ) == 0 )
+ {
+ *pResult = true;
+ }
+ else if( strcmp( pString, CELLULAR_URC_TOKEN_STRING_INPUT_START_PLUS ) == 0 )
+ {
+ *pResult = false;
+ }
+ else
+ {
+ *pResult = false;
+ }
+
+ return atStatus;
+}
+
CellularATError_t _CMOCK_Cellular_ATStrDup_CALLBACK( char ** ppDst,
const char * pSrc,
int cmock_num_calls )
@@ -623,10 +656,45 @@ void test__Cellular_HandlePacket_AT_UNSOLICITED_Happy_Path( void )
/* set for cellularAtParseTokenHandler function */
passCompareString = false;
- pCompareString = getStringAfterColon( CELLULAR_URC_TOKEN_STRING_INPUT_START_PLUS );
+ pCompareString = getStringAfterColon( CELLULAR_URC_TOKEN_STRING_INPUT_WITH_PAYLOAD );
+
+ pktStatus = _Cellular_HandlePacket( &context, AT_UNSOLICITED, CELLULAR_URC_TOKEN_STRING_INPUT_WITH_PAYLOAD );
+ TEST_ASSERT_EQUAL( CELLULAR_PKT_STATUS_OK, pktStatus );
+ TEST_ASSERT_EQUAL( true, passCompareString );
+}
+
+/**
+ * @brief Test input string without payload for _Cellular_HandlePacket.
+ *
+ * URC input string "+RDY" should be regarded as URC without prefix.
+ * If there is a handler function registered in the table, the handler function is
+ * called with pInputStr point to "+RDY" string.
+ */
+void test__Cellular_HandlePacket_AT_UNSOLICITED_Input_String_without_payload( void )
+{
+ CellularContext_t context;
+ CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
+ CellularAtParseTokenMap_t cellularTestUrcHandlerTable[] =
+ {
+ /* Use the URC string instead of the URC prefix in the mapping table. */
+ { CELLULAR_URC_TOKEN_STRING_INPUT_START_PLUS, cellularAtParseTokenHandler }
+ };
+
+ memset( &context, 0, sizeof( CellularContext_t ) );
+ context.tokenTable.pCellularUrcHandlerTable = cellularTestUrcHandlerTable;
+ context.tokenTable.cellularPrefixToParserMapSize = 1;
+
+ Cellular_ATStrDup_StubWithCallback( _CMOCK_Cellular_ATStrDup_CALLBACK );
+
+ /* set for cellularAtParseTokenHandler function */
+ passCompareString = false;
+ pCompareString = CELLULAR_URC_TOKEN_STRING_INPUT_START_PLUS;
pktStatus = _Cellular_HandlePacket( &context, AT_UNSOLICITED, CELLULAR_URC_TOKEN_STRING_INPUT_START_PLUS );
TEST_ASSERT_EQUAL( CELLULAR_PKT_STATUS_OK, pktStatus );
+
+ /* passCompareString is set to true in cellularAtParseTokenHandler if pCompareString
+ * equals to parameter pInputStr. */
TEST_ASSERT_EQUAL( true, passCompareString );
}