ublox-cellular-base_mno_pr

Revision:
36:d239824bfb8f
Parent:
32:1fc4850f1253
Child:
39:2f8ef6ac16dc
--- a/UbloxCellularBase.cpp	Wed Sep 04 16:29:43 2019 +0500
+++ b/UbloxCellularBase.cpp	Wed Oct 09 15:13:04 2019 +0500
@@ -25,6 +25,7 @@
 #define tr_info(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
 #define tr_warn(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
+#define tr_critical(format, ...) debug("\n" format "\n", ## __VA_ARGS__)
 #endif
 
 /* Array to convert the 3G qual number into a median EC_NO_LEV number.
@@ -493,15 +494,12 @@
     _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING;
 #ifdef TARGET_UBLOX_C030_R412M
     _dev_info.modem_psm_state = AWAKE;
-    _psm_status = false;
+    _psm_status = UNKNOWN;
     _cb_param_psm_going_in = NULL;
     _func_psm_going_in = NULL;
     _cb_param_psm_coming_out = NULL;
     _func_psm_coming_out = NULL;
 #endif
-#ifdef TARGET_UBLOX_C030_R41XM
-    _edrx_configured = false;
-#endif
 }
 
 // Destructor.
@@ -605,10 +603,6 @@
 bool UbloxCellularBase::power_up()
 {
     bool success = false;
-    int at_timeout;
-    LOCK();
-
-    at_timeout = _at_timeout; // Has to be inside LOCK()s
 
     MBED_ASSERT(_at != NULL);
 
@@ -620,31 +614,28 @@
 
     for (int retry_count = 0; !success && (retry_count < 20); retry_count++) {
         //In case of SARA-R4, modem takes a while to turn on, constantly toggling the power pin every ~2 secs causes the modem to never power up.
-        if ( (retry_count % 5) == 0) { 
+        if ( (retry_count % 5) == 0) {
             modem_power_up();
         }
-        wait_ms(500);
-        // Modem tends to spit out noise during power up - don't confuse the parser
-        _at->flush();
-        at_set_timeout(1000);
-        if (_at->send("AT")) {
-            // C027 needs a delay here
-            wait_ms(100);
-            if (_at->recv("OK")) {
-                success = true;
-            }
-        }
-        at_set_timeout(at_timeout);
+        success = is_modem_ready();
     }
 
-    if (success) {
-        // Set the final baud rate
-        if (_at->send("AT+IPR=%d", _baud) && _at->recv("OK")) {
-            // Need to wait for things to be sorted out on the modem side
-            wait_ms(100);
-            ((UARTSerial *)_fh)->set_baud(_baud);
-        }
-        
+    return success;
+}
+
+bool UbloxCellularBase::setup_modem()
+{
+    bool success = false;
+    LOCK();
+
+    MBED_ASSERT(_at != NULL);
+
+    // Set the final baud rate
+    if (_at->send("AT+IPR=%d", _baud) && _at->recv("OK")) {
+        // Need to wait for things to be sorted out on the modem side
+        wait_ms(100);
+        ((UARTSerial *)_fh)->set_baud(_baud);
+
         // Turn off modem echoing and turn on verbose responses
         success = _at->send("ATE0;+CMEE=2") && _at->recv("OK") &&
                   // The following commands are best sent separately
@@ -661,6 +652,43 @@
     return success;
 }
 
+bool UbloxCellularBase::is_modem_ready()
+{
+    bool success = false;
+    int at_timeout;
+    LOCK();
+
+    at_timeout = _at_timeout; // Has to be inside LOCK()s
+
+    MBED_ASSERT(_at != NULL);
+
+    _at->flush();
+    at_set_timeout(1000);
+    if (_at->send("AT")) {
+        // C027 needs a delay here
+        wait_ms(100);
+        if (_at->recv("OK")) {
+            success = true;
+        }
+    }
+    at_set_timeout(at_timeout);
+
+    UNLOCK();
+    return success;
+}
+
+bool UbloxCellularBase::initialize_modem()
+{
+    bool success = false;
+
+    if (power_up()) {
+        success = setup_modem();
+    } else {
+        tr_error("Preliminary modem setup failed.");
+    }
+    return success;
+}
+
 // Power down modem via AT interface.
 void UbloxCellularBase::power_down()
 {
@@ -801,11 +829,11 @@
 // Initialise the modem.
 bool UbloxCellularBase::init(const char *pin)
 {
-	int x;
+    int x;
     MBED_ASSERT(_at != NULL);
 
     if (!_modem_initialised) {
-        if (power_up()) {
+        if (initialize_modem()) {
             tr_info("Modem Ready.");
             if (pin != NULL) {
                 _pin = pin;
@@ -816,29 +844,48 @@
             if (set_functionality_mode(FUNC_AIRPLANE)) {
 #endif
                 if (initialise_sim_card()) {
+#ifdef TARGET_UBLOX_C030_R41XM
                     int mno_profile;
-
+                    if (get_mno_profile(&mno_profile)) {
+#ifdef MBED_CONF_UBLOX_CELL_DEFAULT_MNO_PROFILE
+                        if (set_mno_profile((MNOProfile)MBED_CONF_UBLOX_CELL_DEFAULT_MNO_PROFILE)) {
+                            reboot_modem();
+                            while(is_modem_ready() == false) {
+                                wait_ms(1000);
+                            }
+                            setup_modem();
+                        }
+#endif
+                        if (mno_profile == SW_DEFAULT) {
+                            tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!");
+                            _default_profile_is_set = true;
+                            return false;
+                        }
+                    }
 #ifdef TARGET_UBLOX_C030_R412M
-                    if (_psm_status ==  false) { //psm is not enabled by application yet so disable it at start-up
-                        set_power_saving_mode(0, 0);
+                    int status = 0, periodic_time = 0, active_time = 0;
+                    if (_psm_status == UNKNOWN) {
+                        if (get_power_saving_mode(&status, &periodic_time, &active_time)) {
+                            if (status) { //PSM is already enabled either by a previous run or MNO profile
+                                tr_info("PSM is already enabled, periodic_time %d, active_time %d", periodic_time, active_time);
+                                _psm_status = ENABLED;
+                                if ( !(set_psm_urcs(true)) ) { //enable PSM URCs
+                                    tr_error("Modem does not support PSM URCs, disabling PSM");
+                                    set_power_saving_mode(0, 0);
+                                } else if (!_func_psm_going_in){
+                                    tr_critical("!!PSM IS ENABLED, CALLBACK NOT ATTACHED. PLEASE REGISTER ONE!!");
+                                }
+                            }
+                        }
+                    } else if (_psm_status == ENABLED && !_func_psm_going_in){
+                        tr_critical("!!PSM IS ENABLED, CALLBACK NOT ATTACHED. PLEASE REGISTER ONE!!");
                     }
+#elif TARGET_UBLOX_C030_R410M
+                    disable_psm(); //PSM is currently not supported by driver for R410M due to lack of URCs
 #endif
-#ifdef TARGET_UBLOX_C030_R41XM
                     if (_at->is_idle_mode_enabled() == false) {
                         set_idle_mode(false); //disable idle mode at start up
                     }
-                    if(_edrx_configured == false) {
-                        // A special form of the command can be given as +CEDRXS=3.
-                        // In this form, eDRX will be disabled and data for all parameters in the command +CEDRXS will be removed or,
-                        // if available, set to the manufacturer specific default values.
-                        set_receive_period(3,UbloxCellularBase::EDRXGSM_A_Gb_mode);
-                        set_receive_period(3,UbloxCellularBase::EDRXEUTRAN_WB_S1_mode);
-                        set_receive_period(3,UbloxCellularBase::EDRXEUTRAN_NB_S1_mode);
-                    }
-                    get_receive_period();
-
-                    if (get_mno_profile(&mno_profile))
-                        tr_info("Current MNO profile is: %d", mno_profile);
 #endif
                     if (set_device_identity(&_dev_info.dev) && // Set up device identity
                         device_init(_dev_info.dev)) {// Initialise this device
@@ -933,7 +980,7 @@
                 // This should return quickly but sometimes the status field is not returned
                 // so make the timeout short
                 at_set_timeout(1000);
-                if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\n", &status)) {
+                if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\nOK\n", &status)) {
                     set_rat(status);
                 }
                 at_set_timeout(at_timeout);
@@ -1064,10 +1111,10 @@
     success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei);
     tr_info("DevInfo: IMEI=%s", _dev_info.imei);
 
-	if (success)	{
-		memcpy(imei_to_send,_dev_info.imei,size);
-		imei_to_send[size-1] = '\0';
-	}
+    if (success)    {
+        memcpy(imei_to_send,_dev_info.imei,size);
+        imei_to_send[size-1] = '\0';
+    }
 
     UNLOCK();
     return success;
@@ -1164,6 +1211,13 @@
 //RAT should be set in a detached state (AT+COPS=2)
 bool UbloxCellularBase::set_modem_rat(RAT selected_rat, RAT preferred_rat, RAT second_preferred_rat)
 {
+#ifdef TARGET_UBLOX_C030_R41XM
+    if (_default_profile_is_set == true) {
+        tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!");
+        return false;
+    }
+#endif
+
     bool success = false;
     char command[16] = {0x00};
 
@@ -1197,6 +1251,13 @@
 
 bool UbloxCellularBase::get_modem_rat(int *selected_rat, int *preferred_rat, int *second_preferred_rat)
 {
+#ifdef TARGET_UBLOX_C030_R41XM
+    if (_default_profile_is_set == true) {
+        tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!");
+        return false;
+    }
+#endif
+
     bool success = false;
     char buf[24] = {0x00};
 
@@ -1283,7 +1344,7 @@
     bool return_val = false;
     int current_profile;
     MNOProfile arr[MAX_NUM_PROFILES] = { SW_DEFAULT, SIM_ICCID, ATT, TMO, VODAFONE, DT, STANDARD_EU
-#ifdef  TARGET_UBLOX_C030_R410M
+#ifdef TARGET_UBLOX_C030_R410M
                                          , VERIZON, TELSTRA, CT, SPRINT, TELUS
 #endif
                                        };
@@ -1305,12 +1366,18 @@
 
             LOCK();
             if (_at->send("AT+UMNOPROF=%d", current_profile) && _at->recv("OK")) {
-                tr_error("temporary MNO profile set: %d", current_profile);
+                tr_info("temporary MNO profile set: %d", current_profile);
             }
             UNLOCK();
         }
         LOCK();
         if (_at->send("AT+UMNOPROF=%d", profile) && _at->recv("OK")) {
+            if (profile == SW_DEFAULT) {
+                tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!");
+                _default_profile_is_set = true;
+            } else {
+                _default_profile_is_set = false;
+            }
             return_val = true;
         } else {
             tr_error("unable to set user specified profile");
@@ -1347,7 +1414,7 @@
 bool UbloxCellularBase::set_idle_mode(bool enable)
 {
 #ifdef TARGET_UBLOX_C030_R412M
-    if (_psm_status == true && enable == true) {
+    if (_psm_status == ENABLED && enable == true) {
         return false;
     }
 #endif
@@ -1402,7 +1469,6 @@
     LOCK();
 
     if (_at->send("AT+CEDRXS=%d,%d,\"%s\"", mode, act_type, edrx) && _at->recv("OK")) {
-        _edrx_configured = true;
         status = 0;
     }
     else {
@@ -1514,6 +1580,11 @@
 
 bool UbloxCellularBase::set_band_bitmask(RAT rat, uint64_t bitmask) {
 
+    if (_default_profile_is_set == true) {
+        tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!");
+        return false;
+    }
+
     bool status = false;
     UBandmaskRAT eBandMastRat;
 
@@ -1541,8 +1612,12 @@
 
     return status;
 }
-
-bool UbloxCellularBase::get_band_bitmask(uint64_t *m1_bitmask, uint64_t *nb1_bitmask) {
+bool UbloxCellularBase::get_band_bitmask(uint64_t *m1_bitmask, uint64_t *nb1_bitmask)
+{
+    if (_default_profile_is_set == true) {
+        tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!");
+        return false;
+    }
 
     bool status = false;
     int eBandMastRat0, eBandMastRat1;
@@ -1557,8 +1632,22 @@
 
     return status;
 }
+
+bool UbloxCellularBase::disable_psm()
+{
+    bool return_value = false;
+
+    LOCK();
+    if (_at->send("AT+CPSMS=0") && _at->recv("OK")) {
+        return_value = true;
+    }
+    UNLOCK();
+
+    return return_value;
+}
 #endif //TARGET_UBLOX_C030_R41XM
 
+
 #ifdef TARGET_UBLOX_C030_R412M
 bool UbloxCellularBase::get_power_saving_mode(int *status, int *periodic_time, int *active_time)
 {
@@ -1573,7 +1662,7 @@
 
     LOCK();
     //+UCPSMS:1,,,"01000011","01000011"
-    if (_at->send("AT+UCPSMS?") && _at->recv("+UCPSMS:%d,,,\"%8c\",\"%8c\"\n", status, pt_encoded, at_encoded)) {
+    if (_at->send("AT+UCPSMS?") && _at->recv("+UCPSMS:%d,,,\"%8c\",\"%8c\"\nOK\n", status, pt_encoded, at_encoded)) {
         if (*status == true) {
             //PSM is enabled, decode the timer values, periodic TAU first
             value =  (pt_encoded[7]- '0');
@@ -1671,6 +1760,7 @@
 
 bool UbloxCellularBase::set_power_saving_mode(int periodic_time, int active_time)
 {
+
     if (_at->is_idle_mode_enabled() == true && periodic_time != 0 && active_time != 0 ) {
         return false;
     }
@@ -1680,133 +1770,129 @@
     int at_timeout = _at_timeout;
     at_set_timeout(10000); //AT+CPSMS has response time of < 10s
 
-    //check if modem supports PSM URCs
-    if (_at->send("AT+UPSMR?") && _at->recv("OK")) {
-        if (periodic_time == 0 && active_time == 0) {
-            // disable PSM
-            if (_at->send("AT+CPSMS=0") && _at->recv("OK")) {
-                if (_at->send("AT+UPSMR=0") && _at->recv("OK")) {//disable the URC
-                    //de-register the callback
-                    detach_cb_psm_going_in();
-                    detach_cb_psm_coming_out();
-                    _psm_status = false;
-                    return_val = true;
-                }
-            }
-        } else { //PSM string encoding code borrowed from AT_CellularPower.cpp
-            /**
-                Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element
+    if (periodic_time == 0 && active_time == 0) {
+        // disable PSM
+        if (_at->send("AT+CPSMS=0") && _at->recv("OK")) {
+            set_psm_urcs(false); //disable the URC
+            _psm_status = DISABLED;
+            return_val = true;
+        }
+    } else if (_at->send("AT+UPSMR?") && _at->recv("OK")) { //PSM string encoding code borrowed from AT_CellularPower.cpp
+        /**
+            Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element
 
-                Bits 5 to 1 represent the binary coded timer value.
+            Bits 5 to 1 represent the binary coded timer value.
 
-                Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
-                8 7 6
-                0 0 0 value is incremented in multiples of 10 minutes
-                0 0 1 value is incremented in multiples of 1 hour
-                0 1 0 value is incremented in multiples of 10 hours
-                0 1 1 value is incremented in multiples of 2 seconds
-                1 0 0 value is incremented in multiples of 30 seconds
-                1 0 1 value is incremented in multiples of 1 minute
-                1 1 0 value is incremented in multiples of 320 hours (NOTE 1)
-                1 1 1 value indicates that the timer is deactivated (NOTE 2).
-             */
-            char pt[8+1];// timer value encoded as 3GPP IE
-            const int ie_value_max = 0x1f;
-            uint32_t periodic_timer = 0;
-            if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds
-                periodic_timer = periodic_time/2;
-                strcpy(pt, "01100000");
+            Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
+            8 7 6
+            0 0 0 value is incremented in multiples of 10 minutes
+            0 0 1 value is incremented in multiples of 1 hour
+            0 1 0 value is incremented in multiples of 10 hours
+            0 1 1 value is incremented in multiples of 2 seconds
+            1 0 0 value is incremented in multiples of 30 seconds
+            1 0 1 value is incremented in multiples of 1 minute
+            1 1 0 value is incremented in multiples of 320 hours (NOTE 1)
+            1 1 1 value indicates that the timer is deactivated (NOTE 2).
+         */
+        char pt[8+1];// timer value encoded as 3GPP IE
+        const int ie_value_max = 0x1f;
+        uint32_t periodic_timer = 0;
+        if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds
+            periodic_timer = periodic_time/2;
+            strcpy(pt, "01100000");
+        } else {
+            if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds
+                periodic_timer = periodic_time/30;
+                strcpy(pt, "10000000");
             } else {
-                if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds
-                    periodic_timer = periodic_time/30;
-                    strcpy(pt, "10000000");
+                if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute
+                    periodic_timer = periodic_time/60;
+                    strcpy(pt, "10100000");
                 } else {
-                    if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute
-                        periodic_timer = periodic_time/60;
-                        strcpy(pt, "10100000");
+                    if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes
+                        periodic_timer = periodic_time/(10*60);
+                        strcpy(pt, "00000000");
                     } else {
-                        if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes
-                            periodic_timer = periodic_time/(10*60);
-                            strcpy(pt, "00000000");
+                        if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour
+                            periodic_timer = periodic_time/(60*60);
+                            strcpy(pt, "00100000");
                         } else {
-                            if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour
-                                periodic_timer = periodic_time/(60*60);
-                                strcpy(pt, "00100000");
-                            } else {
-                                if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours
-                                    periodic_timer = periodic_time/(10*60*60);
-                                    strcpy(pt, "01000000");
-                                } else { // multiples of 320 hours
-                                    int t = periodic_time / (320*60*60);
-                                    if (t > ie_value_max) {
-                                        t = ie_value_max;
-                                    }
-                                    periodic_timer = t;
-                                    strcpy(pt, "11000000");
+                            if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours
+                                periodic_timer = periodic_time/(10*60*60);
+                                strcpy(pt, "01000000");
+                            } else { // multiples of 320 hours
+                                int t = periodic_time / (320*60*60);
+                                if (t > ie_value_max) {
+                                    t = ie_value_max;
                                 }
+                                periodic_timer = t;
+                                strcpy(pt, "11000000");
                             }
                         }
                     }
                 }
             }
+        }
 
-            uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, 5);
-            pt[8] = '\0';
+        uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, 5);
+        pt[8] = '\0';
+
+        /**
+            Table 10.5.172/3GPP TS 24.008: GPRS Timer information element
 
-            /**
-                Table 10.5.172/3GPP TS 24.008: GPRS Timer information element
+            Bits 5 to 1 represent the binary coded timer value.
+
+            Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
 
-                Bits 5 to 1 represent the binary coded timer value.
-
-                Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
+            8 7 6
+            0 0 0  value is incremented in multiples of 2 seconds
+            0 0 1  value is incremented in multiples of 1 minute
+            0 1 0  value is incremented in multiples of decihours
+            1 1 1  value indicates that the timer is deactivated.
 
-                8 7 6
-                0 0 0  value is incremented in multiples of 2 seconds
-                0 0 1  value is incremented in multiples of 1 minute
-                0 1 0  value is incremented in multiples of decihours
-                1 1 1  value indicates that the timer is deactivated.
+            Other values shall be interpreted as multiples of 1 minute in this version of the protocol.
+        */
+        char at[8+1];
+        uint32_t active_timer; // timer value encoded as 3GPP IE
+        if (active_time <= 2*ie_value_max) { // multiples of 2 seconds
+            active_timer = active_time/2;
+            strcpy(at, "00000000");
+        } else {
+            if (active_time <= 60*ie_value_max) { // multiples of 1 minute
+                active_timer = (1<<5) | (active_time/60);
+                strcpy(at, "00100000");
+            } else { // multiples of decihours
+                int t = active_time / (6*60);
+                if (t > ie_value_max) {
+                    t = ie_value_max;
+                }
+                active_timer = t;
+                strcpy(at, "01000000");
+            }
+        }
 
-                Other values shall be interpreted as multiples of 1 minute in this version of the protocol.
-            */
-            char at[8+1];
-            uint32_t active_timer; // timer value encoded as 3GPP IE
-            if (active_time <= 2*ie_value_max) { // multiples of 2 seconds
-                active_timer = active_time/2;
-                strcpy(at, "00000000");
+        uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, 5);
+        at[8] = '\0';
+
+        if (_at->send("AT+CPSMS=1,,,\"%s\",\"%s\"", pt, at) && _at->recv("OK")) {
+            if (set_psm_urcs(true)) {//enable the PSM URC
+                tr_info("PSM enabled successfully!");
+                _psm_status = ENABLED;
+                return_val = true;
             } else {
-                if (active_time <= 60*ie_value_max) { // multiples of 1 minute
-                    active_timer = (1<<5) | (active_time/60);
-                    strcpy(at, "00100000");
-                } else { // multiples of decihours
-                    int t = active_time / (6*60);
-                    if (t > ie_value_max) {
-                        t = ie_value_max;
-                    }
-                    active_timer = t;
-                    strcpy(at, "01000000");
-                }
-            }
-
-            uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, 5);
-            at[8] = '\0';
-
-            if (_at->send("AT+CPSMS=1,,,\"%s\",\"%s\"", pt, at) && _at->recv("OK")) {
-                if (_at->send("AT+UPSMR=1") && _at->recv("OK")) {//enable the PSM URC
-                    tr_info("PSM enabled successfully!");
-                    _psm_status = true;
-                    return_val = true;
-                } else {
-                    tr_error("PSM URCs not supported");
-                    return_val = false;
-                }
-            } else {
-                tr_error("+CPSMS command failed");
+                tr_error("Error enabling PSM URCs, PSM not enabled");
+                _at->send("AT+CPSMS=0");
+                _at->recv("OK");
                 return_val = false;
             }
+        } else {
+            tr_error("+CPSMS command failed");
+            return_val = false;
         }
     } else {
         tr_error("PSM URCs not supported by this version of modem");
     }
+
     at_set_timeout(at_timeout);
     UNLOCK();
     return return_val;
@@ -1835,6 +1921,22 @@
 
     UNLOCK();
 }
+
+bool UbloxCellularBase::set_psm_urcs(bool enable)
+{
+
+    bool success = false;
+    LOCK();
+
+    MBED_ASSERT(_at != NULL);
+
+    if (_at->send("AT+UPSMR=%d", enable ? 1 : 0) && _at->recv("OK")) {
+        success = true;
+    }
+
+    UNLOCK();
+    return success;
+}
 #endif
 
 // End of File