Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

Commit 684d948

Browse files
authored
Merge pull request #114 from pycom/lte_psm_three
LTE: Add API for Power Saving Mode
2 parents 20cc45c + 0cdc8e8 commit 684d948

File tree

4 files changed

+188
-7
lines changed

4 files changed

+188
-7
lines changed

esp32/application.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ APP_UTIL_SRC_C = $(addprefix util/,\
186186
timeutils.c \
187187
esp32chipinfo.c \
188188
pycom_general_util.c \
189+
str_utils.c \
189190
)
190191

191192
APP_FATFS_SRC_C = $(addprefix fatfs/src/,\

esp32/mods/modlte.c

Lines changed: 150 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
#include "modmachine.h"
6969
#include "mpirq.h"
7070

71+
#include "str_utils.h"
72+
7173
/******************************************************************************
7274
DEFINE TYPES
7375
******************************************************************************/
@@ -83,6 +85,23 @@
8385

8486
#define SQNS_SW_FULL_BAND_SUPPORT 41000
8587
#define SQNS_SW_5_8_BAND_SUPPORT 39000
88+
89+
// PSM Power saving mode
90+
// PERIOD, aka Requested Periodic TAU (T3412), in GPRS Timer 3 format
91+
#define PSM_PERIOD_2S 0b011
92+
#define PSM_PERIOD_30S 0b100
93+
#define PSM_PERIOD_1M 0b101
94+
#define PSM_PERIOD_10M 0b000
95+
#define PSM_PERIOD_1H 0b001
96+
#define PSM_PERIOD_10H 0b010
97+
#define PSM_PERIOD_320H 0b110
98+
#define PSM_PERIOD_DISABLED 0b111
99+
// ACTIVE, aka Requested Active Time (T3324), in GPRS Timer 2 format
100+
#define PSM_ACTIVE_2S 0b000
101+
#define PSM_ACTIVE_1M 0b001
102+
#define PSM_ACTIVE_6M 0b010
103+
#define PSM_ACTIVE_DISABLED 0b111
104+
86105
/******************************************************************************
87106
DECLARE PRIVATE DATA
88107
******************************************************************************/
@@ -408,7 +427,8 @@ static void TASK_LTE_UPGRADE(void *pvParameters){
408427
// Micro Python bindings; LTE class
409428

410429
static mp_obj_t lte_init_helper(lte_obj_t *self, const mp_arg_val_t *args) {
411-
char at_cmd[LTE_AT_CMD_SIZE_MAX - 4];
430+
const size_t at_cmd_len = LTE_AT_CMD_SIZE_MAX - 4;
431+
char at_cmd[at_cmd_len];
412432
lte_modem_conn_state_t modem_state;
413433

414434
if (lte_obj.init) {
@@ -426,24 +446,23 @@ static mp_obj_t lte_init_helper(lte_obj_t *self, const mp_arg_val_t *args) {
426446
MP_THREAD_GIL_ENTER();
427447
if (E_LTE_MODEM_DISCONNECTED == lteppp_modem_state()) {
428448
xSemaphoreGive(xLTE_modem_Conn_Sem);
429-
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Couldn't connect to Modem!"));
449+
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Couldn't connect to Modem (modem_state=disconnected)"));
430450
}
431451
break;
432452
case E_LTE_MODEM_CONNECTING:
433453
// Block till modem is connected
434454
xSemaphoreTake(xLTE_modem_Conn_Sem, portMAX_DELAY);
435455
if (E_LTE_MODEM_DISCONNECTED == lteppp_modem_state()) {
436456
xSemaphoreGive(xLTE_modem_Conn_Sem);
437-
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Couldn't connect to Modem!"));
457+
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Couldn't connect to Modem (modem_state=connecting)"));
438458
}
439459
break;
440460
case E_LTE_MODEM_CONNECTED:
441461
//continue
442462
break;
443463
default:
444-
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Couldn't connect to Modem!"));
464+
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Couldn't connect to Modem (modem_state=default)"));
445465
break;
446-
447466
}
448467
lte_obj.cid = args[1].u_int;
449468

@@ -490,16 +509,102 @@ static mp_obj_t lte_init_helper(lte_obj_t *self, const mp_arg_val_t *args) {
490509
lteppp_set_state(E_LTE_IDLE);
491510
mod_network_register_nic(&lte_obj);
492511
lte_obj.init = true;
512+
513+
// configure PSM
514+
u8_t psm_period_value = args[4].u_int;
515+
u8_t psm_period_unit = args[5].u_int;
516+
u8_t psm_active_value = args[6].u_int;
517+
u8_t psm_active_unit = args[7].u_int;
518+
if ( psm_period_unit != PSM_PERIOD_DISABLED && psm_active_unit != PSM_ACTIVE_DISABLED ) {
519+
u8_t psm_period = ( psm_period_unit << 5 ) | psm_period_value;
520+
u8_t psm_active = ( psm_active_unit << 5 ) | psm_active_value;
521+
char p[9];
522+
char a[9];
523+
sprint_binary_u8(p, psm_period);
524+
sprint_binary_u8(a, psm_active);
525+
snprintf(at_cmd, at_cmd_len, "AT+CPSMS=1,,,\"%s\",\"%s\"", p, a);
526+
lte_push_at_command(at_cmd, LTE_RX_TIMEOUT_MAX_MS);
527+
}
528+
493529
xSemaphoreGive(xLTE_modem_Conn_Sem);
494530
return mp_const_none;
495531
}
496532

533+
STATIC mp_obj_t lte_psm(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
534+
lte_check_init();
535+
lte_check_inppp();
536+
mp_obj_t tuple[5];
537+
static const qstr psm_info_fields[] = {
538+
MP_QSTR_enabled,
539+
MP_QSTR_period_value,
540+
MP_QSTR_period_unit,
541+
MP_QSTR_active_value,
542+
MP_QSTR_active_unit,
543+
};
544+
545+
lte_push_at_command("AT+CPSMS?", LTE_RX_TIMEOUT_MAX_MS);
546+
const char *resp = modlte_rsp.data;
547+
char *pos;
548+
if ( ( pos = strstr(resp, "+CPSMS: ") ) ) {
549+
// decode the resp:
550+
// +CPSMS: <mode>,[<Requested_Periodic-RAU>],[<Requested_GPRS-READYtimer>],[<Requested_Periodic-TAU>],[<Requested_Active-Time>]
551+
552+
// go to <mode>
553+
pos += strlen_const("+CPSMS: ");
554+
tuple[0] = mp_obj_new_bool(*pos == '1');
555+
556+
// go to <Requested_Periodic-RAU>
557+
pos += strlen_const("1,");
558+
559+
// find <Requested_GPRS-READYtimer>
560+
pos = strstr(pos, ",");
561+
pos++;
562+
563+
// find <Requested_Periodic-TAU>
564+
pos = strstr(pos, ",");
565+
pos++; // ,
566+
pos++; // "
567+
568+
// get three digit TAU unit
569+
char* oldpos = pos;
570+
tuple[2] = mp_obj_new_int_from_str_len( (const char**) &pos, 3, false, 2);
571+
assert( pos == oldpos + 3); // mp_obj_new_int_from_str_len is supposed to consume exactly 3 characters
572+
573+
// get five digit TAU value
574+
tuple[1] = mp_obj_new_int_from_str_len( (const char**) &pos, 5, false, 2);
575+
576+
// find <Requested_Active-Time>
577+
pos = strstr(pos, ",");
578+
pos++; // ,
579+
pos++; // "
580+
581+
// get three digit ActiveTime unit
582+
oldpos = pos;
583+
tuple[4] = mp_obj_new_int_from_str_len( (const char**) &pos, 3, false, 2);
584+
assert( pos == oldpos + 3); // mp_obj_new_int_from_str_len is supposed to consume exactly 3 characters
585+
586+
// get five digit ActiveTime value
587+
tuple[3] = mp_obj_new_int_from_str_len( (const char**) &pos, 5, false, 2);
588+
589+
} else {
590+
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Failed to read PSM setting"));
591+
}
592+
593+
return mp_obj_new_attrtuple(psm_info_fields, 5, tuple);
594+
}
595+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(lte_psm_obj, 1, lte_psm);
596+
597+
497598
static const mp_arg_t lte_init_args[] = {
498599
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
499600
{ MP_QSTR_carrier, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
500601
{ MP_QSTR_cid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
501602
{ MP_QSTR_legacyattach, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
502603
{ MP_QSTR_debug, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
604+
{ MP_QSTR_psm_period_value, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0 } },
605+
{ MP_QSTR_psm_period_unit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PSM_PERIOD_DISABLED } },
606+
{ MP_QSTR_psm_active_value, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0 } },
607+
{ MP_QSTR_psm_active_unit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PSM_ACTIVE_DISABLED } },
503608
};
504609

505610
static mp_obj_t lte_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
@@ -522,6 +627,30 @@ static mp_obj_t lte_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uin
522627
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
523628
}
524629
}
630+
631+
// check psm args
632+
u8_t psm_period_value = args[5].u_int;
633+
u8_t psm_period_unit = args[6].u_int;
634+
u8_t psm_active_value = args[7].u_int;
635+
u8_t psm_active_unit = args[8].u_int;
636+
if (psm_period_unit > 7)
637+
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Invalid psm_period_unit"));
638+
if (psm_period_value > 31)
639+
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Invalid psm_period_value"));
640+
switch(psm_active_unit){
641+
case PSM_ACTIVE_2S:
642+
case PSM_ACTIVE_1M:
643+
case PSM_ACTIVE_6M:
644+
case PSM_ACTIVE_DISABLED:
645+
// ok, nothing to do
646+
break;
647+
default:
648+
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Invalid psm_active_unit"));
649+
break;
650+
}
651+
if (psm_active_value > 31)
652+
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Invalid psm_active_value"));
653+
525654
// start the peripheral
526655
lte_init_helper(self, &args[1]);
527656
return (mp_obj_t)self;
@@ -531,8 +660,7 @@ STATIC mp_obj_t lte_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *k
531660
// parse args
532661
mp_arg_val_t args[MP_ARRAY_SIZE(lte_init_args) - 1];
533662
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &lte_init_args[1], args);
534-
if (args[3].u_bool)
535-
lte_debug = true;
663+
lte_debug = args[3].u_bool;
536664
return lte_init_helper(pos_args[0], args);
537665
}
538666
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(lte_init_obj, 1, lte_init);
@@ -1407,6 +1535,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(lte_events_obj, lte_events);
14071535
STATIC const mp_map_elem_t lte_locals_dict_table[] = {
14081536
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&lte_init_obj },
14091537
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&lte_deinit_obj },
1538+
{ MP_OBJ_NEW_QSTR(MP_QSTR_psm), (mp_obj_t)&lte_psm_obj },
14101539
{ MP_OBJ_NEW_QSTR(MP_QSTR_attach), (mp_obj_t)&lte_attach_obj },
14111540
{ MP_OBJ_NEW_QSTR(MP_QSTR_dettach), (mp_obj_t)&lte_detach_obj },
14121541
{ MP_OBJ_NEW_QSTR(MP_QSTR_detach), (mp_obj_t)&lte_detach_obj }, /* backward compatibility for dettach method FIXME */
@@ -1435,6 +1564,20 @@ STATIC const mp_map_elem_t lte_locals_dict_table[] = {
14351564
{ MP_OBJ_NEW_QSTR(MP_QSTR_IP), MP_OBJ_NEW_QSTR(MP_QSTR_IP) },
14361565
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPV4V6), MP_OBJ_NEW_QSTR(MP_QSTR_IPV4V6) },
14371566
{ MP_OBJ_NEW_QSTR(MP_QSTR_EVENT_COVERAGE_LOSS), MP_OBJ_NEW_SMALL_INT(LTE_TRIGGER_SIG_LOST) },
1567+
// PSM Power Saving Mode
1568+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_PERIOD_2S), MP_OBJ_NEW_SMALL_INT(PSM_PERIOD_2S) },
1569+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_PERIOD_30S), MP_OBJ_NEW_SMALL_INT(PSM_PERIOD_30S) },
1570+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_PERIOD_1M), MP_OBJ_NEW_SMALL_INT(PSM_PERIOD_1M) },
1571+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_PERIOD_10M), MP_OBJ_NEW_SMALL_INT(PSM_PERIOD_10M) },
1572+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_PERIOD_1H), MP_OBJ_NEW_SMALL_INT(PSM_PERIOD_1H) },
1573+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_PERIOD_10H), MP_OBJ_NEW_SMALL_INT(PSM_PERIOD_10H) },
1574+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_PERIOD_320H), MP_OBJ_NEW_SMALL_INT(PSM_PERIOD_320H) },
1575+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_PERIOD_DISABLED), MP_OBJ_NEW_SMALL_INT(PSM_PERIOD_DISABLED) },
1576+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_ACTIVE_2S), MP_OBJ_NEW_SMALL_INT(PSM_ACTIVE_2S) },
1577+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_ACTIVE_1M), MP_OBJ_NEW_SMALL_INT(PSM_ACTIVE_1M) },
1578+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_ACTIVE_6M), MP_OBJ_NEW_SMALL_INT(PSM_ACTIVE_6M) },
1579+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PSM_ACTIVE_DISABLED), MP_OBJ_NEW_SMALL_INT(PSM_ACTIVE_DISABLED) },
1580+
14381581
};
14391582
STATIC MP_DEFINE_CONST_DICT(lte_locals_dict, lte_locals_dict_table);
14401583

esp32/util/str_utils.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include "str_utils.h"
2+
#include <stdio.h>
3+
4+
/**
5+
* Create a string representation of a uint8
6+
*/
7+
void sprint_binary_u8(char* s, uint8_t v){
8+
size_t len = 9; // eight bits plus '\0'
9+
snprintf(s, len, "%u%u%u%u%u%u%u%u",
10+
(v & 0b10000000) >> 7,
11+
(v & 0b01000000) >> 6,
12+
(v & 0b00100000) >> 5,
13+
(v & 0b00010000) >> 4,
14+
(v & 0b00001000) >> 3,
15+
(v & 0b00000100) >> 2,
16+
(v & 0b00000010) >> 1,
17+
(v & 0b00000001) >> 0
18+
);
19+
}
20+

esp32/util/str_utils.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef STR_UTILS_H
2+
#define STR_UTILS_H
3+
4+
#include <stddef.h>
5+
#include <stdint.h>
6+
7+
/**
8+
* Determine the length of str at compile time
9+
*
10+
* The length is excluding the terminating \0 just as strlen()
11+
* make sure you pass a compile time constant
12+
*/
13+
#define strlen_const(string) (sizeof(string)-1)
14+
15+
void sprint_binary_u8(char* s, uint8_t v);
16+
17+
#endif

0 commit comments

Comments
 (0)