68
68
#include "modmachine.h"
69
69
#include "mpirq.h"
70
70
71
+ #include "str_utils.h"
72
+
71
73
/******************************************************************************
72
74
DEFINE TYPES
73
75
******************************************************************************/
83
85
84
86
#define SQNS_SW_FULL_BAND_SUPPORT 41000
85
87
#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
+
86
105
/******************************************************************************
87
106
DECLARE PRIVATE DATA
88
107
******************************************************************************/
@@ -408,7 +427,8 @@ static void TASK_LTE_UPGRADE(void *pvParameters){
408
427
// Micro Python bindings; LTE class
409
428
410
429
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 ];
412
432
lte_modem_conn_state_t modem_state ;
413
433
414
434
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) {
426
446
MP_THREAD_GIL_ENTER ();
427
447
if (E_LTE_MODEM_DISCONNECTED == lteppp_modem_state ()) {
428
448
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) " ));
430
450
}
431
451
break ;
432
452
case E_LTE_MODEM_CONNECTING :
433
453
// Block till modem is connected
434
454
xSemaphoreTake (xLTE_modem_Conn_Sem , portMAX_DELAY );
435
455
if (E_LTE_MODEM_DISCONNECTED == lteppp_modem_state ()) {
436
456
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) " ));
438
458
}
439
459
break ;
440
460
case E_LTE_MODEM_CONNECTED :
441
461
//continue
442
462
break ;
443
463
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) " ));
445
465
break ;
446
-
447
466
}
448
467
lte_obj .cid = args [1 ].u_int ;
449
468
@@ -490,16 +509,102 @@ static mp_obj_t lte_init_helper(lte_obj_t *self, const mp_arg_val_t *args) {
490
509
lteppp_set_state (E_LTE_IDLE );
491
510
mod_network_register_nic (& lte_obj );
492
511
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
+
493
529
xSemaphoreGive (xLTE_modem_Conn_Sem );
494
530
return mp_const_none ;
495
531
}
496
532
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
+
497
598
static const mp_arg_t lte_init_args [] = {
498
599
{ MP_QSTR_id , MP_ARG_INT , {.u_int = 0 } },
499
600
{ MP_QSTR_carrier , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_obj = mp_const_none } },
500
601
{ MP_QSTR_cid , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 1 } },
501
602
{ MP_QSTR_legacyattach , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = true} },
502
603
{ 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 } },
503
608
};
504
609
505
610
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
522
627
nlr_raise (mp_obj_new_exception_msg (& mp_type_OSError , mpexception_os_resource_not_avaliable ));
523
628
}
524
629
}
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
+
525
654
// start the peripheral
526
655
lte_init_helper (self , & args [1 ]);
527
656
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
531
660
// parse args
532
661
mp_arg_val_t args [MP_ARRAY_SIZE (lte_init_args ) - 1 ];
533
662
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 ;
536
664
return lte_init_helper (pos_args [0 ], args );
537
665
}
538
666
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);
1407
1535
STATIC const mp_map_elem_t lte_locals_dict_table [] = {
1408
1536
{ MP_OBJ_NEW_QSTR (MP_QSTR_init ), (mp_obj_t )& lte_init_obj },
1409
1537
{ 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 },
1410
1539
{ MP_OBJ_NEW_QSTR (MP_QSTR_attach ), (mp_obj_t )& lte_attach_obj },
1411
1540
{ MP_OBJ_NEW_QSTR (MP_QSTR_dettach ), (mp_obj_t )& lte_detach_obj },
1412
1541
{ 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[] = {
1435
1564
{ MP_OBJ_NEW_QSTR (MP_QSTR_IP ), MP_OBJ_NEW_QSTR (MP_QSTR_IP ) },
1436
1565
{ MP_OBJ_NEW_QSTR (MP_QSTR_IPV4V6 ), MP_OBJ_NEW_QSTR (MP_QSTR_IPV4V6 ) },
1437
1566
{ 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
+
1438
1581
};
1439
1582
STATIC MP_DEFINE_CONST_DICT (lte_locals_dict , lte_locals_dict_table );
1440
1583
0 commit comments