Skip to content
This repository has been archived by the owner on Nov 11, 2024. It is now read-only.

Commit

Permalink
A different tack: try AT+CEER instead.
Browse files Browse the repository at this point in the history
Test: 12.0 cellNet
  • Loading branch information
RobMeades committed Jan 29, 2024
1 parent f8b8278 commit 8b5f9c5
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 162 deletions.
12 changes: 6 additions & 6 deletions cell/api/u_cell_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -761,15 +761,15 @@ int32_t uCellNetSetBaseStationConnectionStatusCallback(uDeviceHandle_t cellHandl
uCellNetStatus_t uCellNetGetNetworkStatus(uDeviceHandle_t cellHandle,
uCellNetRegDomain_t domain);

/** Get the last EMM reject cause sent by the network; only
* supported on SARA-R5.
/** Get the last EMM cause value sent by the network and then
* reset it to zero.
*
* @param cellHandle the handle of the cellular instance.
* @return on success an EMM reject cause from 3GPP
* TS 24.301 (zero if there is no reject
* cause), else negative error code.
* @return on success the last cause from the network,
* see appendix A.3 of the AT commands manual,
* else negative error code.
*/
int32_t uCellNetGetLastEmmRejectCause(uDeviceHandle_t cellHandle);
int32_t uCellNetGetResetEmmCause(uDeviceHandle_t cellHandle);

/** Get a value indicating whether the module is registered on
* the network, roaming or home networks.
Expand Down
214 changes: 109 additions & 105 deletions cell/src/u_cell_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,61 +601,59 @@ static void CEREG_urc(uAtClientHandle_t atHandle, void *pParameter)
int32_t periodicWakeupSeconds = -1;
int32_t assumed3gppRat = 7; // LTE

if (!pInstance->ignoreCeregUrc) {
if (!(pInstance->pModule->supportedRatsBitmap & (1UL << (int32_t) U_CELL_NET_RAT_LTE)) &&
(pInstance->pModule->supportedRatsBitmap & (1UL << (int32_t) U_CELL_NET_RAT_CATM1))) {
// Assumed RAT has to be Cat-M1 if we don't support LTE
assumed3gppRat = 8; // Cat-M1
}

status = CXREG_urc(pInstance, U_CELL_PRIVATE_NET_REG_TYPE_CEREG, assumed3gppRat);
if (U_CELL_NET_STATUS_MEANS_REGISTERED(status) &&
(pSleepContext != NULL)) {
// If we have a sleep context, try to read the
// parameters from the end of +CEREG also
// CXREG_urc() will have read up to and including
// the parameter indicating the active RAT, next
// skip the <cause_type> and <reject_cause> parameters
uAtClientSkipParameters(atHandle, 2);
// Now read the active time, T3324, as a string, and decode it
bytesRead = uAtClientReadString(atHandle, encoded, sizeof(encoded), false);
if (bytesRead > 0) {
uCellPwrPrivateActiveTimeStrToSeconds(encoded, &activeTimeSeconds);
}
// Read the periodic wake-up time, T3412 ext, as a string,
// and decode it
bytesRead = uAtClientReadString(atHandle, encoded, sizeof(encoded), false);
if (bytesRead > 0) {
uCellPwrPrivatePeriodicWakeupStrToSeconds(encoded, true,
&periodicWakeupSeconds);
}
onNotOff = (activeTimeSeconds >= 0);
// Update the 3GPP power saving status in the sleep context
pSleepContext->powerSaving3gppAgreed = onNotOff;
// Inform the user if there is a callback and the parameters have changed
if ((pSleepContext->p3gppPowerSavingCallback != NULL) &&
//lint -e(731) Suppress use of Boolean argument in comparison
((pSleepContext->powerSaving3gppOnNotOffCereg != onNotOff) ||
(pSleepContext->activeTimeSecondsCereg != activeTimeSeconds) ||
(pSleepContext->periodicWakeupSecondsCereg != periodicWakeupSeconds))) {
// Put all the data in a struct and pass a pointer to it to our
// local callback via the AT client's callback mechanism to decouple
// it from whatever might have called us.
// Note: powerSaving3gppCallback will free the allocated memory.
pCallback = (uCellNet3gppPowerSavingCallback_t *) pUPortMalloc(sizeof(*pCallback));
if (pCallback != NULL) {
pCallback->cellHandle = pInstance->cellHandle;
pCallback->pCallback = pSleepContext->p3gppPowerSavingCallback;
pCallback->onNotOff = onNotOff;
pCallback->activeTimeSeconds = activeTimeSeconds;
pCallback->periodicWakeupSeconds = periodicWakeupSeconds;
pCallback->pCallbackParam = pSleepContext->p3gppPowerSavingCallbackParam;
uAtClientCallback(pInstance->atHandle, powerSaving3gppCallback, pCallback);
// Set the stored parameters to the ones we just received
pSleepContext->powerSaving3gppOnNotOffCereg = onNotOff;
pSleepContext->activeTimeSecondsCereg = activeTimeSeconds;
pSleepContext->periodicWakeupSecondsCereg = periodicWakeupSeconds;
}
if (!(pInstance->pModule->supportedRatsBitmap & (1UL << (int32_t) U_CELL_NET_RAT_LTE)) &&
(pInstance->pModule->supportedRatsBitmap & (1UL << (int32_t) U_CELL_NET_RAT_CATM1))) {
// Assumed RAT has to be Cat-M1 if we don't support LTE
assumed3gppRat = 8; // Cat-M1
}

status = CXREG_urc(pInstance, U_CELL_PRIVATE_NET_REG_TYPE_CEREG, assumed3gppRat);
if (U_CELL_NET_STATUS_MEANS_REGISTERED(status) &&
(pSleepContext != NULL)) {
// If we have a sleep context, try to read the
// parameters from the end of +CEREG also
// CXREG_urc() will have read up to and including
// the parameter indicating the active RAT, next
// skip the <cause_type> and <reject_cause> parameters
uAtClientSkipParameters(atHandle, 2);
// Now read the active time, T3324, as a string, and decode it
bytesRead = uAtClientReadString(atHandle, encoded, sizeof(encoded), false);
if (bytesRead > 0) {
uCellPwrPrivateActiveTimeStrToSeconds(encoded, &activeTimeSeconds);
}
// Read the periodic wake-up time, T3412 ext, as a string,
// and decode it
bytesRead = uAtClientReadString(atHandle, encoded, sizeof(encoded), false);
if (bytesRead > 0) {
uCellPwrPrivatePeriodicWakeupStrToSeconds(encoded, true,
&periodicWakeupSeconds);
}
onNotOff = (activeTimeSeconds >= 0);
// Update the 3GPP power saving status in the sleep context
pSleepContext->powerSaving3gppAgreed = onNotOff;
// Inform the user if there is a callback and the parameters have changed
if ((pSleepContext->p3gppPowerSavingCallback != NULL) &&
//lint -e(731) Suppress use of Boolean argument in comparison
((pSleepContext->powerSaving3gppOnNotOffCereg != onNotOff) ||
(pSleepContext->activeTimeSecondsCereg != activeTimeSeconds) ||
(pSleepContext->periodicWakeupSecondsCereg != periodicWakeupSeconds))) {
// Put all the data in a struct and pass a pointer to it to our
// local callback via the AT client's callback mechanism to decouple
// it from whatever might have called us.
// Note: powerSaving3gppCallback will free the allocated memory.
pCallback = (uCellNet3gppPowerSavingCallback_t *) pUPortMalloc(sizeof(*pCallback));
if (pCallback != NULL) {
pCallback->cellHandle = pInstance->cellHandle;
pCallback->pCallback = pSleepContext->p3gppPowerSavingCallback;
pCallback->onNotOff = onNotOff;
pCallback->activeTimeSeconds = activeTimeSeconds;
pCallback->periodicWakeupSeconds = periodicWakeupSeconds;
pCallback->pCallbackParam = pSleepContext->p3gppPowerSavingCallbackParam;
uAtClientCallback(pInstance->atHandle, powerSaving3gppCallback, pCallback);
// Set the stored parameters to the ones we just received
pSleepContext->powerSaving3gppOnNotOffCereg = onNotOff;
pSleepContext->activeTimeSecondsCereg = activeTimeSeconds;
pSleepContext->periodicWakeupSecondsCereg = periodicWakeupSeconds;
}
}
}
Expand Down Expand Up @@ -1063,6 +1061,35 @@ static int32_t readNextScanItem(uCellPrivateInstance_t *pInstance,
return errorCodeOrNumber;
}

// Read the last EMM cause sent by the network.
static int32_t getEmmCause(const uCellPrivateInstance_t *pInstance)
{
int32_t errorCodeOrEmmCause;
uAtClientHandle_t atHandle = pInstance->atHandle;
int32_t x = -1;
char buffer[32]; // Enough room for "EMM cause"

uAtClientLock(atHandle);
uAtClientCommandStart(atHandle, "AT+CEER");
uAtClientCommandStop(atHandle);
// Should get back +CEER: <type>[,<cause>,<error_description>]
uAtClientResponseStart(atHandle, "+CEER:");
// Read <type>
uAtClientReadString(atHandle, buffer, sizeof(buffer), false);
// Read <cause>
x = uAtClientReadInt(atHandle);
// Skip <error_description>
uAtClientSkipParameters(atHandle, 1);
uAtClientResponseStop(atHandle);
errorCodeOrEmmCause = uAtClientUnlock(atHandle);
if ((errorCodeOrEmmCause == 0) && (x >= 0) &&
(strncmp(buffer, "EMM cause", sizeof(buffer)) == 0)) {
errorCodeOrEmmCause = x;
}

return errorCodeOrEmmCause;
}

// Handle the response to the CxREG command, where regType
// is an index into gRegTypes[].
static void handleCxRegResponse(uCellPrivateInstance_t *pInstance, int32_t regType)
Expand Down Expand Up @@ -2464,6 +2491,10 @@ int32_t uCellNetConnect(uDeviceHandle_t cellHandle,
} while ((errorCode != 0) && (pApnConfig != NULL) &&
(*pApnConfig != '\0') && keepGoingLocalCb(pInstance));


// Populate, or reset, the last EMM cause
pInstance->lastEmmCause = getEmmCause(pInstance);

if (errorCode == 0) {
// Remember the MCC/MNC in case we need to deactivate
// and reactivate context later and that causes
Expand All @@ -2489,7 +2520,6 @@ int32_t uCellNetConnect(uDeviceHandle_t cellHandle,
// Take away the callback again
pInstance->pKeepGoingCallback = NULL;
pInstance->startTimeMs = 0;

}
} else {
uPortLog("U_CELL_NET: already connected.\n");
Expand Down Expand Up @@ -2554,6 +2584,9 @@ int32_t uCellNetRegister(uDeviceHandle_t cellHandle,
errorCode = waitAttach(pInstance);
}

// Populate, or reset, the last EMM cause
pInstance->lastEmmCause = getEmmCause(pInstance);

if (errorCode == 0) {
// Remember the MCC/MNC in case we need to deactivate
// and reactivate context later and that causes
Expand All @@ -2577,7 +2610,6 @@ int32_t uCellNetRegister(uDeviceHandle_t cellHandle,
// Take away the callback again
pInstance->pKeepGoingCallback = NULL;
pInstance->startTimeMs = 0;

}
}

Expand Down Expand Up @@ -2740,6 +2772,8 @@ int32_t uCellNetActivate(uDeviceHandle_t cellHandle,
uPortLog(" (no APN specified).\n");
}
}
// Populate, or reset, the last EMM cause
pInstance->lastEmmCause = getEmmCause(pInstance);
}
}

Expand Down Expand Up @@ -2793,6 +2827,8 @@ int32_t uCellNetDeactivate(uDeviceHandle_t cellHandle,
if (errorCode != 0) {
uPortLog("U_CELL_NET: unable to deactivate context.\n");
}
// Populate, or reset, the last EMM cause
pInstance->lastEmmCause = getEmmCause(pInstance);
}
}

Expand Down Expand Up @@ -2845,6 +2881,8 @@ int32_t uCellNetDisconnect(uDeviceHandle_t cellHandle,
} else {
uPortLog("U_CELL_NET: unable to disconnect.\n");
}
// Populate, or reset, the last EMM cause
pInstance->lastEmmCause = getEmmCause(pInstance);
}

U_PORT_MUTEX_UNLOCK(gUCellPrivateMutex);
Expand Down Expand Up @@ -3266,69 +3304,35 @@ uCellNetStatus_t uCellNetGetNetworkStatus(uDeviceHandle_t cellHandle,
return (uCellNetStatus_t) errorCodeOrStatus;
}

// Get the last EMM reject cause sent by the network.
int32_t uCellNetGetLastEmmRejectCause(uDeviceHandle_t cellHandle)
// Get the last EMM cause sent by the network.
int32_t uCellNetGetResetEmmCause(uDeviceHandle_t cellHandle)
{
int32_t errorCodeOrEmmRejectCause = (int32_t) U_ERROR_COMMON_NOT_INITIALISED;
int32_t errorCodeOrEmmCause = (int32_t) U_ERROR_COMMON_NOT_INITIALISED;
uCellPrivateInstance_t *pInstance;
uAtClientHandle_t atHandle;
int32_t x = -1;

if (gUCellPrivateMutex != NULL) {

U_PORT_MUTEX_LOCK(gUCellPrivateMutex);

pInstance = pUCellPrivateGetInstance(cellHandle);
errorCodeOrEmmRejectCause = (int32_t) U_ERROR_COMMON_INVALID_PARAMETER;
errorCodeOrEmmCause = (int32_t) U_ERROR_COMMON_INVALID_PARAMETER;
if (pInstance != NULL) {
errorCodeOrEmmRejectCause = (int32_t) U_ERROR_COMMON_NOT_SUPPORTED;
if (pInstance->pModule->moduleType == U_CELL_MODULE_TYPE_SARA_R5) {
// Figuring out the logic for getting the reject cause in a URC
// that would work with all of the other ridiculous logic concerning
// registration status would make a horrible problem a horrible
// problem squared. Instead we temporarily set the +CEREG
// type to 5 and set a flag which will cause us to ignore
// any +CEREG URCs that happen while we do so.
pInstance->ignoreCeregUrc = true;
atHandle = pInstance->atHandle;
uAtClientLock(atHandle);
uAtClientCommandStart(atHandle, "AT+CEREG=5");
uAtClientCommandStopReadResponse(atHandle);
uAtClientCommandStart(atHandle, "AT+CEREG?");
uAtClientCommandStop(atHandle);
// Should get back +CEREG: <n>,<stat>[,[<tac>],[<ci>],[<AcT>[,[<cause_type>],[<reject_cause>][,[<Assigned_Active_Time>,[<Assigned_Periodic_TAU>]]]]]]
uAtClientResponseStart(atHandle, "+CEREG:");
// Skip past <n>,<stat>,<tac>,<ci>,<AcT>
uAtClientSkipParameters(atHandle, 5);
// <cause_type> must be 0
if (uAtClientReadInt(atHandle) == 0) {
// Read <reject_cause>
x = uAtClientReadInt(atHandle);
}
// Put the registration state back again
uAtClientResponseStop(atHandle);
uAtClientCommandStart(atHandle, "AT+CEREG=");
uAtClientWriteInt(atHandle, U_CELL_NET_CEREG_TYPE);
uAtClientCommandStopReadResponse(atHandle);
errorCodeOrEmmRejectCause = uAtClientUnlock(atHandle);
if ((errorCodeOrEmmRejectCause == 0) && (x >= 0)) {
errorCodeOrEmmRejectCause = x;
}
pInstance->ignoreCeregUrc = false;
// Query the registration state so that the normal code
// catches up with any changes in registration status
uAtClientLock(atHandle);
uAtClientCommandStart(atHandle, "AT+CEREG?");
uAtClientCommandStop(atHandle);
handleCxRegResponse(pInstance, 2 /* CEREG */);
uAtClientUnlock(atHandle);
// Retrieve the stored value, which may hold a
// reject cause from a registration atttempt
errorCodeOrEmmCause = pInstance->lastEmmCause;
if (errorCodeOrEmmCause == 0) {
// If there wasn't a stored value, check again
// in case something has happened since
errorCodeOrEmmCause = getEmmCause(pInstance);
}
// Reset the cause value now that it has been read
pInstance->lastEmmCause = 0;
}

U_PORT_MUTEX_UNLOCK(gUCellPrivateMutex);
}

return errorCodeOrEmmRejectCause;
return errorCodeOrEmmCause;
}

// Get a value whether the module is registered on the network.
Expand Down
2 changes: 1 addition & 1 deletion cell/src/u_cell_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ typedef struct uCellPrivateInstance_t {
networkStatus[U_CELL_PRIVATE_NET_REG_TYPE_MAX_NUM]; /**< Registation status for each type, separating CREG, CGREG and CEREG. */
uCellNetRat_t
rat[U_CELL_PRIVATE_NET_REG_TYPE_MAX_NUM]; /**< The active RAT for each registration type. */
bool ignoreCeregUrc; /**< Used on SARA-R5 for uCellNetGetLastEmmRejectCause() only. */
int32_t lastEmmCause; /**< Used by uCellNetGetEmmCause() only. */
uCellPrivateRadioParameters_t radioParameters; /**< The radio parameters. */
int32_t startTimeMs; /**< Used while connecting and scanning. */
int32_t connectedAtMs; /**< When a connection was last established,
Expand Down
Loading

0 comments on commit 8b5f9c5

Please sign in to comment.