upsv

Revision:
23:eaab8e812a5d
Parent:
22:779971811c46
Child:
24:e26a6ab0dd75
--- a/UbloxCellularBase.cpp	Wed Apr 10 12:05:55 2019 +0500
+++ b/UbloxCellularBase.cpp	Fri May 03 13:43:49 2019 +0500
@@ -143,6 +143,25 @@
     _dev_info.reg_status_eps = static_cast<NetworkRegistrationStatusEps>(status);
 }
 
+#ifdef TARGET_UBLOX_C030_R412M
+void UbloxCellularBase::set_modem_psm_state(int status)
+{
+    switch (status) {
+        case ASLEEP:
+            tr_info("Modem is going in PSM sleep");
+            break;
+        case AWAKE:
+            tr_info("Modem is awake from PSM sleep");
+            break;
+        default:
+            tr_info("Unknown PSM state. %d", status);
+            break;
+    }
+
+    _dev_info.modem_psm_state = static_cast<ModemPSMState>(status);
+}
+#endif
+
 void UbloxCellularBase::set_rat(int acTStatus)
 {
     switch (acTStatus) {
@@ -384,6 +403,30 @@
     read_at_to_char(buf, sizeof (buf), '\n');
 }
 
+#ifdef TARGET_UBLOX_C030_R412M
+// Callback UUPSMR, set/clear flag for modem psm state.
+void UbloxCellularBase::UUPSMR_URC()
+{
+    int status;
+    char buf[10];
+
+    if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
+        if (sscanf(buf, ": %d", &status) == 1) {
+            set_modem_psm_state(status);
+            //call application registered callbacks
+            if (status == AWAKE) { //modem coming out of sleep
+                if (_func_psm_coming_out) {
+                    _func_psm_coming_out(_cb_param_psm_coming_out);
+                }
+            } else if(status == ASLEEP) { //modem going into sleep
+                if (_func_psm_going_in) {
+                    _func_psm_going_in(_cb_param_psm_going_in);
+                }
+            }
+        }
+    }
+}
+#endif
 /**********************************************************************
  * PROTECTED METHODS
  **********************************************************************/
@@ -448,6 +491,14 @@
     _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING;
     _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING;
     _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING;
+#ifdef TARGET_UBLOX_C030_R412M
+    _dev_info.modem_psm_state = AWAKE;
+    _psm_status = false;
+    _cb_param_psm_going_in = NULL;
+    _func_psm_going_in = NULL;
+    _cb_param_psm_coming_out = NULL;
+    _func_psm_coming_out = NULL;
+#endif
 }
 
 // Destructor.
@@ -496,6 +547,10 @@
 
         // Capture the UMWI, just to stop it getting in the way
         _at->oob("+UMWI", callback(this, &UbloxCellularBase::UMWI_URC));
+#ifdef TARGET_UBLOX_C030_R412M
+        // Handle PSM URC for going in and coming out of PSM
+        _at->oob("+UUPSMR", callback(this, &UbloxCellularBase::UUPSMR_URC));
+#endif
     }
 }
 
@@ -611,12 +666,12 @@
 
     if (_modem_initialised && (_at != NULL)) {
         int at_timeout = _at_timeout; // Save previous timeout
-    	_at->set_timeout(1000);
-    	// Check modem is powered off
-    	if(_at->send("AT") && _at->recv("OK")) {
+        _at->set_timeout(1000);
+        // Check modem is powered off
+        if(_at->send("AT") && _at->recv("OK")) {
             _at->send("AT+CPWROFF") && _at->recv("OK");
-    	}
-    	_at->set_timeout(at_timeout);
+        }
+        _at->set_timeout(at_timeout);
     }
 
     _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING;
@@ -748,6 +803,11 @@
                 _pin = pin;
             }
             if (initialise_sim_card()) {
+#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);
+                }
+#endif
                 if (set_device_identity(&_dev_info.dev) && // Set up device identity
                     device_init(_dev_info.dev)) {// Initialise this device
                     // Get the integrated circuit ID of the SIM
@@ -1127,7 +1187,7 @@
     return success;
 }
 
-// Power down modem via AT interface.
+//application should call init() or connect() in order to initialize the modem
 bool UbloxCellularBase::reboot_modem()
 {
     bool return_val = false;
@@ -1207,6 +1267,295 @@
     return return_val;
 }
 #endif
+#ifdef TARGET_UBLOX_C030_R412M
+bool UbloxCellularBase::get_power_saving_mode(int *status, int *periodic_time, int *active_time)
+{
+    char pt_encoded[8+1];// timer value encoded as 3GPP IE
+    char at_encoded[8+1];// timer value encoded as 3GPP IE
+    int value, multiplier;
+    bool return_val;
 
+    LOCK();
+    //+UCPSMS:1,,,"01000011","01000011"
+    if (_at->send("AT+UCPSMS?") && _at->recv("+UCPSMS:%d,,,\"%8c\",\"%8c\"\n", status, pt_encoded, at_encoded)) {
+        if (*status == true) {
+            //PSM is enabled, decode the timer values, periodic TAU first
+            value =  (pt_encoded[7]- '0');
+            value += (pt_encoded[6]- '0') << 1;
+            value += (pt_encoded[5]- '0') << 2;
+            value += (pt_encoded[4]- '0') << 3;
+            value += (pt_encoded[3]- '0') << 4;
+
+            multiplier =  (pt_encoded[2]- '0');
+            multiplier += (pt_encoded[1]- '0') << 1;
+            multiplier += (pt_encoded[0]- '0') << 2;
+
+            switch(multiplier) {
+                //10 minutes
+                case 0:
+                    value = value*10*60;
+                break;
+
+                //1 hour
+                case 1:
+                    value = value*60*60;
+                break;
+
+                //10 hours
+                case 2:
+                    value = value*10*60*60;
+                break;
+
+                //2 seconds
+                case 3:
+                    value = value*2;
+                break;
+
+                //30 seconds
+                case 4:
+                    value = value*30;
+                break;
+
+                //1 minute
+                case 5:
+                    value = value*60;
+                break;
+
+                //320 hours
+                case 6:
+                    value = value*320*60*60;
+                break;
+
+                default:
+                    value = 0;
+                break;
+            }
+            *periodic_time = value;
+
+            //decode the active time
+            value =  (at_encoded[7]- '0');
+            value += (at_encoded[6]- '0') << 1;
+            value += (at_encoded[5]- '0') << 2;
+            value += (at_encoded[4]- '0') << 3;
+            value += (at_encoded[3]- '0') << 4;
+
+            multiplier =  (at_encoded[2]- '0');
+            multiplier += (at_encoded[1]- '0') << 1;
+            multiplier += (at_encoded[0]- '0') << 2;
+
+            switch(multiplier) {
+                //2 seconds
+                case 0:
+                    value = value*2;
+                break;
+
+                //1 minute
+                case 1:
+                    value = value*60;
+                break;
+
+                //decihours (6minutes)
+                case 2:
+                    value = value*6*60;
+                break;
+
+                default:
+                    value = 0;
+                break;
+            }
+            *active_time = value;
+        }
+        return_val = true;
+    } else {
+        return_val = false;
+    }
+    UNLOCK();
+    return return_val;
+}
+
+bool UbloxCellularBase::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
+
+    //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
+
+                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")) {
+                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");
+                return_val = false;
+            }
+        }
+    } else {
+        tr_error("PSM URCs not supported by this version of modem");
+    }
+    at_set_timeout(at_timeout);
+    UNLOCK();
+    return return_val;
+}
+
+void UbloxCellularBase::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 UbloxCellularBase::is_modem_awake()
+{
+  return (_dev_info.modem_psm_state == AWAKE);
+}
+
+//application should call init() or connect() in order to initialize the modem
+void UbloxCellularBase::wakeup_modem()
+{
+    LOCK();
+
+    MBED_ASSERT(_at != NULL);
+
+    tr_info("Waking up modem...");
+
+    modem_power_up();
+
+    _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING;
+    _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING;
+    _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING;
+    _modem_initialised = false;
+
+    UNLOCK();
+}
+#endif
 // End of File