Base class for the ublox-xxx-cellular-xxx classes. Cannot be used standalone, only inherited by classes that do properly useful stuff. Or, to put it another way, if you are using any of the ublox-xxx-cellular-xxx classes, you will need this class also.

Dependents:   example-ublox-cellular-interface example-ublox-cellular-driver-gen HelloMQTT example-ublox-cellular-interface_r410M ... more

Files at this revision

API Documentation at this revision

Comitter:
wajahat.abbas@u-blox.com
Date:
Wed Oct 09 15:13:04 2019 +0500
Parent:
32:1fc4850f1253
Child:
35:24f29bf0d810
Commit message:
Application should not use MNO profile 0

Changed in this revision

UbloxCellularBase.cpp Show annotated file Show diff for this revision Revisions of this file
UbloxCellularBase.h Show annotated file Show diff for this revision Revisions of this file
mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
--- 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
--- a/UbloxCellularBase.h	Wed Sep 04 16:29:43 2019 +0500
+++ b/UbloxCellularBase.h	Wed Oct 09 15:13:04 2019 +0500
@@ -187,12 +187,12 @@
      */
     bool change_sim_pin(const char *new_pin);
 
-	/** Get the IMEI.
+    /** Get the IMEI.
      *
      * @return true if successful, otherwise false.
      */
     MBED_DEPRECATED("This method is now replaced by const char * imei(), please use that instead")
-	bool get_imei(char *imei_to_send, int size);
+    bool get_imei(char *imei_to_send, int size);
 
     /** Get the IMEI of the module.
      *
@@ -259,23 +259,20 @@
     } FunctionalityMode;
 
 #ifdef TARGET_UBLOX_C030_R41XM
-
-    #if MBED_CONF_UBLOX_CELL_DEFAULT_MNO_PROFILE
-    #define DEFAULT_MNO_PROFILE     (MNOProfile)MBED_CONF_UBLOX_CELL_DEFAULT_MNO_PROFILE
-    #else
-    #define DEFAULT_MNO_PROFILE     SW_DEFAULT
-    #endif
-
-    /** Reads the current MNO profile from modem and sets it to user specified profile.
-     * User can also specify profile in mbed_lib.json file and call set_mno_profile without any arguments.
+    /** Set MNO profile. Profile will be applied on next boot.
+     *
+     * User can also specify profile in mbed_lib.json ("default-mno-profile": 100) and in that case profile will be applied in init().
+     * Modem will also be rebooted so that profile parameters can be applied.
      *
      * Note: MNO profile should only be set in detached state and a reboot is required for settings to take effect
      * Note 2: ref to UBX-17003787 B.5, setting MNO profile can change other parameters such as PSM, Band mask, URAT etc.
      *         Application must always set a profile first and if required, change parameters afterwards.
+     * Note 3: ref to UBX-17003787 B.5, some profiles have locked parameters and modem will return ERROR if you try to change those.
+     *         It is suggested to switch to a profile e.g. STANDARD_EU (100) and then change the parameters as required.
      * @param profile MNO profile to use
      * @return    true if operation was successful, false if there was an error
      */
-    bool set_mno_profile(MNOProfile profile = DEFAULT_MNO_PROFILE);
+    bool set_mno_profile(MNOProfile profile);
 
     /** Get current MNO profile.
      *
@@ -492,6 +489,12 @@
      *  @return           True if successful, otherwise false.
      */
     bool get_band_bitmask(uint64_t *m1_bitmask, uint64_t *nb1_bitmask);
+
+    /** disables the PSM
+     *
+     *  @return           True if successful, otherwise false.
+     */
+    bool disable_psm();
 #endif
 
 protected:
@@ -690,6 +693,24 @@
      */
     bool power_up();
 
+    /** Setup the modem baudrate, echo and flow control
+     *
+     * @return true if successful, otherwise false.
+     */
+    bool setup_modem();
+
+    /** Check if modem is accepting AT commands
+     *
+     * @return true if successful, otherwise false.
+     */
+    bool is_modem_ready();
+
+    /** Powers up the modem and set it up for application use.
+     *
+     * @return true if successful, otherwise false.
+     */
+    bool initialize_modem();
+
     /** Power down the modem.
      */
     void power_down();
@@ -773,8 +794,14 @@
     void CEREG_URC();
     void UMWI_URC();
 #ifdef TARGET_UBLOX_C030_R412M
+    typedef enum {
+       DISABLED = 0,
+       ENABLED = 1,
+       UNKNOWN = 2
+    } PSMStatus;
+    bool set_psm_urcs(bool enable);
     void UUPSMR_URC();
-    bool _psm_status;
+    PSMStatus _psm_status;
     void *_cb_param_psm_going_in;
     Callback<void(void*)>    _func_psm_going_in;  /**< Callback. */
     void *_cb_param_psm_coming_out;
@@ -782,7 +809,7 @@
     void set_modem_psm_state(int state);
 #endif
 #ifdef TARGET_UBLOX_C030_R41XM
-    bool _edrx_configured;
+    bool _default_profile_is_set;
 #endif
 };
 
--- a/mbed_lib.json	Wed Sep 04 16:29:43 2019 +0500
+++ b/mbed_lib.json	Wed Oct 09 15:13:04 2019 +0500
@@ -3,7 +3,6 @@
     "config": {
         "baud-rate": 115200,
         "at-parser-buffer-size": 256,
-        "at-parser-timeout": 8000,
-        "default-mno-profile": 0
+        "at-parser-timeout": 8000
     }
 }