Skip to content

Commit

Permalink
Add CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR config (#117)
Browse files Browse the repository at this point in the history
* Update cellular library to MIT license

* Add CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR to support different modem

* Differnt modem may use different leading char for prefix string. Add
  config CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR to support.
* Use Cellular_ATIsPrefixPresent to check URC with prefix in pkthandler

* Fix CI failures

* Fix lecicon

* Add test case to coverage URC string only with leading char

* Fix lexicon

* Fix lexicon space

* Update comments

* include CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR in
  CELLULAR_CHECK_IS_PREFIX_CHAR

* Fix bug
  • Loading branch information
chinglee-iot authored Nov 8, 2022
1 parent 92702e5 commit 936d4f7
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 18 deletions.
41 changes: 39 additions & 2 deletions docs/doxygen/portingCellularModule.dox
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,10 @@ They can be used to reduce porting effort. <br>
@page cellular_module_urc_handler cellular_module_urc_handler
@brief Implement URC handler to handle URC event and call the corresponding callback function. <br>
- @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
<br>

<b>Example URC handler table</b>:
```
CellularAtParseTokenMap_t CellularUrcHandlerTable[] =
{
Expand All @@ -179,9 +181,44 @@ CellularAtParseTokenMap_t CellularUrcHandlerTable[] =
}
uint32_t CellularUrcHandlerTableSize = 4;
```
<br>
There are two types of URC strings can be handled with this table:
- <b>URC with prefix</b><br>
This type of URC string is of the following format:<br>
> <b>\<URC_leading_char\>\<URC_prefix\>":"\<URC_payload\></b><br>
The logic to check the URC prefix can be referenced in @ref Cellular_ATIsPrefixPresent<br>
Example of URC with prefix: <b>"+CREG:2,0"</b><br>
In this example, <br>
<b>URC_leading_char</b> is "+"<br>
<b>URC_prefix</b> is "CREG"<br>
<b>URC_payload</b> is "2,0"<br>
The URC callback function, @ref CellularAtParseTokenHandler_t, will be called with
parameter <b>pInputStr</b> point to string URC_payload, <b>"2,0"</b> in this example.
> The default prefix leading char can be referenced in this config @ref CELLULAR_CHECK_IS_PREFIX_LEADING_CHAR.<br>
> The default valid prefix string chars can be referenced in this config @ref CELLULAR_CHECK_IS_PREFIX_CHAR.<br>
> Reference @subpage cellular_prefix_string_customize_config for more information.

- <b>URC without prefix</b><br>
This type of URC string is of fixed format.<br>
Example of URC without prefix : <b>"NORMAL POWER DOWN"</b><br>
The URC callback function, @ref CellularAtParseTokenHandler_t, will be called with
parameter <b>pInputStr</b> point to URC string, <b>"NORMAL POWER DOWN"</b> in this example.
<br>

@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. <br>

@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}
Expand Down
5 changes: 5 additions & 0 deletions lexicon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ firmwareversion
freertos
freertosconfig
fucntion
fso
functionpointers
fw
gcc
Expand Down Expand Up @@ -468,6 +469,7 @@ parsetimezoneinfo
parseyearmonthdayincclkresponse
partialdata
partialdatarcvdlen
passcomparestring
patbuf
patcmd
patcommandpayload
Expand Down Expand Up @@ -495,6 +497,7 @@ pcomminterface
pcomminterfacehandle
pcommintf
pcontext
pcomparestring
pcurrentcmd
pcwriteto
pdata
Expand Down Expand Up @@ -529,6 +532,7 @@ phexdata
pinputbuf
pinputline
pinputptr
pinputstr
pitm
pkio
pkt
Expand Down Expand Up @@ -751,6 +755,7 @@ simcardstate
simlockstate
sinr
sms
smso
snprintf
socketclose
socketconnect
Expand Down
13 changes: 4 additions & 9 deletions source/cellular_at_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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. */
Expand Down
20 changes: 14 additions & 6 deletions source/cellular_pkthandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

Expand All @@ -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 )
{
Expand Down
39 changes: 39 additions & 0 deletions source/include/cellular_config_defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,45 @@
#define CELLULAR_CONFIG_MAX_PREFIX_STRING_LENGTH ( 32U )
#endif

/**
* @brief Macro to check prefix leading char.<br>
*
* 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.<br>
*
* <b>Default value (if undefined):</b> '+'
*
* For example:
* > ^SMSO:(list of supported<fso>s)<br>
* The prefix string contains <b>"^"</b> 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.<br>
*
* The macro to check prefix string contains valid char. Modem with different prefix
* strings can be supported with this config.<br>
*
* <b>Default value (if undefined):</b> alphabet, digit, '+' and '_'
*
* For example:
* > +APP PDP: 0,ACTIVE<br>
* 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.
Expand Down
19 changes: 19 additions & 0 deletions test/unit-test/cellular_at_core_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ============================ */
Expand Down Expand Up @@ -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 );
}
70 changes: 69 additions & 1 deletion test/unit-test/cellular_pkthandler_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 "+"
Expand Down Expand Up @@ -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 )
Expand Down Expand Up @@ -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 );
}

Expand Down

0 comments on commit 936d4f7

Please sign in to comment.