GNSS

Dependents:   ublox-at-cellular-interface-ext

Fork of ublox-at-cellular-interface by u-blox

Branch:
r410m_psm
Revision:
17:b43a3b85353f
Parent:
15:8cc9a80ac0ad
Child:
24:c6592eec499a
--- a/UbloxATCellularInterface.cpp	Wed Jun 06 16:42:02 2018 +0500
+++ b/UbloxATCellularInterface.cpp	Wed Sep 05 14:39:52 2018 +0500
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 
+
 #include "UbloxATCellularInterface.h"
 #include "mbed_poll.h"
 #include "nsapi.h"
@@ -410,6 +411,269 @@
     return success;
 }
 
+#ifdef TARGET_UBLOX_C030_R410M
+bool UbloxATCellularInterface::set_power_saving_mode(int periodic_time, int active_time, Callback<void()> func)
+{
+    if (set_power_saving_mode(60, 20)) {
+        _at->attach(func);
+    }
+
+}
+bool UbloxATCellularInterface::set_power_saving_mode(int periodic_time, int active_time)
+{
+    bool return_val = false;
+
+    LOCK();
+    int at_timeout = _at_timeout;
+    at_set_timeout(10000); //AT+CPSMS has response time of < 10s
+
+    if (periodic_time == 0 && active_time == 0) {
+        // disable PSM
+        if (_at->send("AT+CPSMS=0") && _at->recv("OK")) {
+            return_val = true;
+            _at->set_psm_status(false);
+        } else {
+            return_val = false;
+        }
+    } else {
+        /**
+            Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 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:
+            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 <= 60*ie_value_max) { // multiples of 1 minute
+                    periodic_timer = periodic_time/60;
+                    strcpy(pt, "10100000");
+                } else {
+                    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 <= 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");
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        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
+
+            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.
+
+            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");
+            }
+        }
+
+        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")) {
+            at_set_timeout(3*60*1000); //send reboot command
+            if (_at->send("AT+CFUN=15") && _at->recv("OK")) {
+                //wait untill modem is back up
+                for (int retry_count = 0; retry_count < 20; retry_count++) {
+                    wait_ms(500);
+                    _at->flush();
+                    at_set_timeout(1000);
+                    if (_at->send("AT")) {
+                        // C027 needs a delay here
+                        wait_ms(100);
+                        if (_at->recv("OK")) {
+                            return_val = _at->send("ATE0;+CMEE=2") && _at->recv("OK") &&
+                                    // The following commands are best sent separately
+                                    _at->send("AT&K0") && _at->recv("OK") && // Turn off RTC/CTS handshaking
+                                    _at->send("AT&C1") && _at->recv("OK") && // Set DCD circuit(109), changes in accordance with the carrier detect status
+                                    _at->send("AT&D0") && _at->recv("OK"); // Set DTR circuit, we ignore the state change of DTR
+                            if (return_val == true) {
+                                _at->set_psm_status(true);
+                            }
+                            break;
+                        }
+                    }
+                }
+            } else {
+                tr_error("modem failed to reboot");
+                return_val = false;
+            }
+        } else {
+            tr_error("+CPSMS command failed");
+            return_val = false;
+        }
+    }
+    at_set_timeout(at_timeout);
+    UNLOCK();
+    return return_val;
+}
+
+void UbloxATCellularInterface::uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt)
+{
+    if (!str || str_size < bit_cnt) {
+        return;
+    }
+    int tmp, pos = 0;
+
+    for (int i = 31; i >= 0; i--) {
+        tmp = num >> i;
+        if (i < bit_cnt) {
+            if (tmp&1) {
+                str[pos] = 1 + '0';
+            } else {
+                str[pos] = 0 + '0';
+            }
+            pos++;
+        }
+    }
+}
+
+bool UbloxATCellularInterface::modem_psm_wake_up()
+{
+    bool success = false;
+    int at_timeout;
+    LOCK();
+
+    at_timeout = _at_timeout;
+    MBED_ASSERT(_at != NULL);
+
+    for (int retry_count = 0; !success && (retry_count < 20); retry_count++) {
+        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);
+    }
+
+    if (!success) {
+        tr_error("modem failed to wakeup from PSM");
+    }
+
+    UNLOCK();
+    return success;
+}
+/*
+bool UbloxATCellularInterface::set_mno_profile(MNOProfile profile)
+{
+    bool return_val = false;
+
+    LOCK();
+    int at_timeout = _at_timeout;
+
+    at_set_timeout(3*60*1000); //response time of AT+COPS=2
+    if (_at->send("AT+COPS=2") && _at->recv("OK")) {
+
+        at_set_timeout(1000);
+        if (_at->send("AT+UMNOPROF=%d", profile) && _at->recv("OK")) {
+
+            at_set_timeout(3*60*1000); //send reboot command
+            if (_at->send("AT+CFUN=15") && _at->recv("OK")) {
+
+                //wait untill modem is back up
+                for (int retry_count = 0; retry_count < 20; retry_count++) {
+                    wait_ms(500);
+                    _at->flush();
+                    at_set_timeout(1000);
+                    if (_at->send("AT")) {
+                        // C027 needs a delay here
+                        wait_ms(100);
+                        if (_at->recv("OK")) {
+                            return_val = true;
+                            break;
+                        }
+                    }
+                }
+            } else {
+                tr_error("modem failed to reboot");
+                return_val = false;
+            }
+        } else {
+            tr_error("+UMNOPROF command failed");
+            return_val = false;
+        }
+    } else {
+        tr_error("+COPS command failed");
+        return_val = false;
+    }
+
+    at_set_timeout(at_timeout);
+    UNLOCK();
+    return return_val;
+}*/
+#endif
+
 /**********************************************************************
  * PROTECTED METHODS: NETWORK INTERFACE and SOCKETS
  **********************************************************************/
@@ -1078,6 +1342,12 @@
 
     // Set up modem and then register with the network
     if (init()) {
+
+#ifdef TARGET_UBLOX_C030_R410M
+        tr_info("PSM disabled at startup");
+        set_power_saving_mode(0, 0);
+#endif
+
         nsapi_error = NSAPI_ERROR_NO_CONNECTION;
         // Perform any pending SIM actions
         if (_sim_pin_check_change_pending) {