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
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
u-blox