ublox-cellular-base_mno_pr
Diff: UbloxCellularBase.cpp
- Revision:
- 23:eaab8e812a5d
- Parent:
- 22:779971811c46
- Child:
- 24:e26a6ab0dd75
diff -r 779971811c46 -r eaab8e812a5d UbloxCellularBase.cpp --- 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