/*================================================================ Copyright (c) 2021, Quectel Wireless Solutions Co., Ltd. All rights reserved. Quectel Wireless Solutions Proprietary and Confidential. =================================================================*/ #include "ql_atcmd.h" #include "ql_sim.h" #include "ci_sim.h" #include "connect_management.h" //#include "quec_atcmd_sim.h" #include "string_utils.h" #include "usim_config.h" #include "quec_cust_feature.h" #if QUEC_MEMORY_OPTIMIZE #define sim_log(msg, ...) custom_log("SIM_LOG", "[SIM_LOG]"##msg, ##__VA_ARGS__) #else #define sim_log(msg, ...) custom_log("SIM_LOG", msg, ##__VA_ARGS__) #endif #define AT_CMD_PREFFIX "AT" #define AT_CMD_NAME_CNUM "+CNUM" #define AT_CMD_NAME_QCCID "+QCCID" #define AT_CMD_NAME_CIMI "+CIMI" #define AT_CMD_NAME_CPOL "+CPOL" #define AT_CMD_NAME_CPIN "+CPIN" #define AT_CMD_NAME_CPWD "+CPWD" #define AT_CMD_NAME_CLCK "+CLCK" #define AT_CMD_NAME_EUICC "*EUICC" #define AT_CMD_NAME_EPIN "+EPIN" #define AT_CMD_NAME_CPBS "+CPBS" #define AT_CMD_NAME_CPBR "+CPBR" #define AT_CMD_NAME_CPBW "+CPBW" #define AT_CMD_NAME_CRSM "+CRSM" #define AT_CMD_NAME_CCHO "+CCHO" #define AT_CMD_NAME_CCHC "+CCHC" #define AT_CMD_NAME_CGLA "+CGLA" #define AT_CMD_SUFFIX "\r\n" #define QUEC_NV_DUAL_SIM_SINGLE_IMEI_SUPPORT "quec_nv_dual_sim_single_imei.dat" static unsigned char ql_dsss_imei_flag = 0; //0-Not support dual sim single IMEI; 1-Support static uint8_t *QL_SIM_PHONE_BOOK_STORAGE_STR[]={ "DC", "EN", "FD", "LD", "MC", "ME", "MT", "ON", "RC", "SM", "AP", "MBDN", "MN", "ICI", "SDN", "OCI", }; extern char IMSI[QL_SIM_IMSI_LEN]; extern UINT8 ICCID[QL_SIM_ICCID_LEN]; extern CiSimPinState gSimPinState; extern CiSimStatus gSimStatus; #if defined(QUEC_DUAL_SIM_SUPPORT) || defined(QUEC_PS_SINGLE_PHYSICAL_DUAL_SIM_SUPPORT) || defined(QUEC_DUAL_SINGLE_PS_SUPPORT) #if defined(QUEC_DUAL_SIM_SUPPORT) || defined(QUEC_PS_SINGLE_PHYSICAL_DUAL_SIM_SUPPORT) extern char IMSI_1[QL_SIM_IMSI_LEN]; extern UINT8 ICCID_1[QL_SIM_ICCID_LEN]; extern CiSimPinState gSimPinState_1; extern CiSimStatus gSimStatus_1; extern UINT32 read_usim_swap_flag(void); static QL_SIM_ERROR_CODE ql_sim_get_card_status_ex(CiSimStatus *card_status, CMSimID_ex sim_id); //Added by Freddy @220201022 清除SIM卡状态信息 void ql_sim_info_clear(void) { //mia.zhong @20210209 更改初始状态,避免识别成锁PIN gSimPinState = CI_SIM_PIN_NUM_STATES; gSimPinState_1 = CI_SIM_PIN_NUM_STATES; gSimStatus = CI_SIM_ST_NOT_READY; gSimStatus_1 = CI_SIM_ST_NOT_READY; } //add switchsim callback QL_SIM_ERROR_CODE ql_sim_switch_card_ex(CMSimID_ex simID, SwitchSimDoneCb cb) { int ret = 0; #if !defined(NO_DIALER) || defined(QUEC_PS_SINGLE_PHYSICAL_DUAL_SIM_SUPPORT) #ifndef SINGLE_SIM ret = CM_SetMasterSimID(simID, cb); #else ret = CM_SetSingleSimID((CMSimID)simID, cb); #endif if (ret == 0) { #if defined(CRANE_DSS) || defined(SINGLE_SIM) //Add by Freddy @20200905 切卡之后需要清掉上一次的网络信息 extern void ql_nw_info_clear(void); ql_nw_info_clear(); #endif return QL_SIM_SUCCESS; } else #endif return QL_SIM_GENERIC_FAILURE; } //mia.zhong @20201130 新增获取卡信息接口 QL_SIM_ERROR_CODE ql_sim_get_simcard_info(QL_SIMCARD_INFO *pt_info, CMSimID_ex sim_id) { QL_SIM_STATUS card_status = QL_SIM_STATUS_NOT_INSERTED; QL_SIM_ERROR_CODE ret = QL_SIM_SUCCESS; int i=0; char resp[64]={0}; UINT8 low_nibble, high_nibble; if(pt_info==NULL) { return QL_SIM_GENERIC_FAILURE; } memset(pt_info,0,sizeof(QL_SIMCARD_INFO)); //get card status ret = ql_sim_get_card_status_ex(&card_status, sim_id); if (ret != QL_SIM_SUCCESS) { sim_log("get card status failed!\n"); return QL_SIM_GENERIC_FAILURE; } else if (card_status != QL_SIM_STATUS_READY) { sim_log("current card status is not QL_SIM_STATUS_READY! card_status=%d\n", card_status); return QL_SIM_GENERIC_FAILURE; } pt_info->card_status = card_status; //printf("pt_info->card_status = %d %x\n", pt_info->card_status, &(pt_info->card_status)); //get imsi if((sim_id == QL_SIM_0) && strlen(IMSI)) { strncpy(pt_info->imsi,IMSI,strlen(IMSI)); } else if((sim_id == QL_SIM_1) && strlen(IMSI_1)) { strncpy(pt_info->imsi,IMSI_1,strlen(IMSI_1)); } else { sim_log("get imsi failed!\n"); return QL_SIM_GENERIC_FAILURE; } //get iccid for (i = 0; i < QL_SIM_ICCID_LEN; i++) { #ifdef QUEC_DUAL_SIM_SUPPORT low_nibble = (((sim_id == QL_SIM_0) ? ICCID : ICCID_1))[i] & 0x0f; high_nibble = ((((sim_id == QL_SIM_0) ? ICCID : ICCID_1))[i] & 0xf0) >> 4; #else low_nibble = (ICCID[i] & 0x0f); high_nibble = (ICCID[i] & 0xf0) >> 4; #endif sprintf(resp, "%s%X%X", resp, low_nibble, high_nibble); } if(strlen(resp)) { strncpy((char *)(pt_info->iccid),resp,QL_SIM_ICCID_LEN*2+1); } else { sim_log("get iccid failed!\n"); return QL_SIM_GENERIC_FAILURE; } //get phonenum return QL_SIM_SUCCESS; } static QL_SIM_ERROR_CODE ql_sim_get_card_status_ex(QL_SIM_STATUS *card_status, CMSimID_ex sim_id) { #if defined(QUEC_DUAL_SIM_SUPPORT) && !defined(NO_DIALER) extern SimSwitchCtx gCmSimSwitchCtx; SimSwitchCtx *ctx = &gCmSimSwitchCtx; if (ctx->state != CM_SIM_SWITCH_INIT) { *card_status=QL_SIM_STATUS_UNKNOWN; return QL_SIM_SUCCESS; } switch ( (sim_id == QL_SIM_0) ? gSimPinState : gSimPinState_1) #else switch ( gSimPinState ) #endif { case CI_SIM_PIN_ST_READY: #ifdef QUEC_DUAL_SIM_SUPPORT if (( (sim_id == QL_SIM_0) ? gSimStatus : gSimStatus_1) == CI_SIM_ST_READY) #else if (gSimStatus == CI_SIM_ST_READY) #endif { *card_status=QL_SIM_STATUS_READY; } break; case CI_SIM_PIN_ST_UNIVERSALPIN_REQUIRED: case CI_SIM_PIN_ST_CHV1_REQUIRED: *card_status=QL_SIM_STATUS_SIM_PIN; break; case CI_SIM_PIN_ST_CHV2_REQUIRED: *card_status=QL_SIM_STATUS_SIM_PIN2; break; case CI_SIM_PIN_ST_UNBLOCK_UNIVERSALPIN_REQUIRED: case CI_SIM_PIN_ST_UNBLOCK_CHV1_REQUIRED: *card_status=QL_SIM_STATUS_SIM_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_CHV2_REQUIRED: *card_status=QL_SIM_STATUS_SIM_PUK2; break; case CI_SIM_PIN_ST_HIDDENKEY_REQUIRED: *card_status=QL_SIM_STATUS_PH_FSIM_PIN; break; case CI_SIM_PIN_ST_UNBLOCK_HIDDENKEY_REQUIRED: *card_status=QL_SIM_STATUS_PH_FSIM_PUK; break; case CI_SIM_PIN_ST_PCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_SIM_LOCK_PIN; break; case CI_SIM_PIN_ST_NCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_NET_PIN; break; case CI_SIM_PIN_ST_NSCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_NET_SUB_PIN; break; case CI_SIM_PIN_ST_SPCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_SP_PIN; break; case CI_SIM_PIN_ST_CCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_CORP_PIN; break; case CI_SIM_PIN_ST_UNBLOCK_PCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_SIM_LOCK_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_NCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_NET_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_NSCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_NET_SUB_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_SPCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_SP_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_CCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_CORP_PUK; break; case CI_SIM_PIN_ST_CHV1_BLOCKED: case CI_SIM_PIN_ST_CHV2_BLOCKED: case CI_SIM_PIN_ST_UNIVERSALPIN_BLOCKED: case CI_SIM_PIN_ST_UNBLOCK_CHV1_BLOCKED: case CI_SIM_PIN_ST_UNBLOCK_CHV2_BLOCKED: case CI_SIM_PIN_ST_UNBLOCK_UNIVERSALPIN_BLOCKED: *card_status=QL_SIM_STATUS_BLOCKED; break; case CI_SIM_PIN_ST_REMOVED: *card_status=QL_SIM_STATUS_NOT_INSERTED; break; case CI_SIM_PIN_ST_WAIT_INITIALISATION: *card_status=QL_SIM_STATUS_BUSY; break; case CI_SIM_PIN_ST_NETWORK_REJECTED: #ifdef QUEC_DUAL_SIM_SUPPORT if (( (sim_id == QL_SIM_0) ? gSimStatus : gSimStatus_1) == CI_SIM_ST_READY) #else if (gSimStatus == CI_SIM_ST_READY) #endif { *card_status=QL_SIM_STATUS_READY; } else { *card_status=QL_SIM_STATUS_UNKNOWN; } break; case CI_SIM_PIN_ST_MEP_ERROR: case CI_SIM_PIN_ST_UDP_ERROR: case CI_SIM_PIN_ST_CPHS_ERROR: case CI_SIM_PIN_ST_INIT_FAILED: case CI_SIM_PIN_ST_GENERAL_ERROR: default: *card_status=QL_SIM_STATUS_UNKNOWN; break; } return QL_SIM_SUCCESS; } #endif int ql_sim_get_cur_SimId(void) { if(CHIP_IS_CRANELRH || CHIP_IS_CRANELG) { int ret = 0; char at_cmd_str[32]={0}; char resp[32]={0}; char para[32]={0}; CMSimID gSimID = NUM_OF_CM_SIM; snprintf(at_cmd_str,sizeof(at_cmd_str)-1,"AT+QDSIM?%s",AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,resp,sizeof(resp),NULL,10); if(ret==QL_AT_RESP_OK) { ql_atcmd_get_para_value_str(resp,0,0,para,sizeof(para)); gSimID=(CMSimID)atoi(para); } return (ret==QL_AT_RESP_OK)?gSimID:-1; } else { #if !defined(NO_DIALER) || defined(QUEC_PS_SINGLE_PHYSICAL_DUAL_SIM_SUPPORT) #ifndef SINGLE_SIM return (isMasterSim0() ? SIM1: SIM2); #else CMSimID gSimID = NUM_OF_CM_SIM; gSimID = (CMSimID)read_usim_swap_flag(); return gSimID; #endif #else return -1; #endif } } int ql_sim_switch_card(int simID) { int ret = 0; if(CHIP_IS_CRANELRH || CHIP_IS_CRANELG) { char at_cmd_str[32]={0}; char resp[32]={0}; snprintf(at_cmd_str,sizeof(at_cmd_str)-1,"AT+QDSIM=%d%s",simID,AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,10); return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } else { #if !defined(NO_DIALER) || defined(QUEC_PS_SINGLE_PHYSICAL_DUAL_SIM_SUPPORT) #ifndef SINGLE_SIM ret = CM_SetMasterSimID(simID, NULL); #else ret = CM_SetSingleSimID((CMSimID)simID, NULL); #endif if (ret == 0) { #ifdef CRANE_DSS //Add by Freddy @20200905 切卡之后需要清掉上一次的网络信息 extern void ql_nw_info_clear(void); ql_nw_info_clear(); #endif //changed by mia.zhong @20201201 切卡之后不再清掉card status //ql_sim_info_clear(); } #endif return ret; } } #endif QL_SIM_ERROR_CODE ql_sim_get_imsi(char *imsi,size_t imsi_len)// NOT SUPPORTED { int card_status; ql_sim_get_card_status(&card_status); if(card_status!=QL_SIM_STATUS_READY) return QL_SIM_GENERIC_FAILURE; memset(imsi,0,imsi_len); //changed by mia.zhong @20201201 if (isMasterSim0() && strlen(IMSI)) { strncpy(imsi,IMSI,imsi_len); return QL_SIM_SUCCESS; } #ifdef QUEC_DUAL_SIM_SUPPORT else if (!isMasterSim0() && strlen(IMSI_1)) { strncpy(imsi,IMSI_1,imsi_len); return QL_SIM_SUCCESS; } #endif else return QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_get_iccid(char *iccid,size_t iccid_len) { int i=0; char resp[64]={0}; UINT8 low_nibble, high_nibble; int card_status; ql_sim_get_card_status(&card_status); if(card_status!=QL_SIM_STATUS_READY) return QL_SIM_GENERIC_FAILURE; memset(iccid,0,iccid_len); for (i = 0; i < 10; i++) { //add by freddy @20201019 双卡时ICCID需要分开处理 #ifdef QUEC_DUAL_SIM_SUPPORT low_nibble = ((isMasterSim0() ? ICCID : ICCID_1))[i] & 0x0f; high_nibble = (((isMasterSim0() ? ICCID : ICCID_1))[i] & 0xf0) >> 4; #else low_nibble = (ICCID[i] & 0x0f); high_nibble = (ICCID[i] & 0xf0) >> 4; #endif sprintf(resp, "%s%X%X", resp, low_nibble, high_nibble); } if(strlen(resp)) { strncpy(iccid,resp,iccid_len); return QL_SIM_SUCCESS; } else return QL_SIM_GENERIC_FAILURE; } #define QL_SIM_READ_RECORD 0xB2 #define QL_SIM_EF_MSISDN 0x6f40 #define QL_SIM_READ_P1 1 #define QL_SIM_READ_P2 4 #define QL_SIM_READ_LEN 28 typedef struct { char l_byte; char h_byte; }ql_sim_ef_praser_t; typedef struct { char bcd_len_l; char bcd_len_h; char ton_npi_l; char ton_npi_h; }ql_sim_ef_header_t; QL_SIM_ERROR_CODE ql_sim_get_phonenumber(char *phonenumber,size_t phonenumber_len) { int ret = 0; char temp[2] = {0}; char atcmd[64]={0}; char resp[128] ={0}; char para[128]={0}; uint32_t len = 0; int i = 0; ql_sim_ef_praser_t *praser = NULL; //praser ptr ql_sim_ef_header_t *header = NULL; //EF MSISDN vaild data hear area ptr if(phonenumber == NULL ){ return QL_SIM_GENERIC_FAILURE; } memset(phonenumber, 0 , phonenumber_len); // EF_MSISDN read by crsm command -TS 27.007 [8.18] snprintf(atcmd, sizeof(atcmd), "AT+CRSM=%d,%d,%d,%d,%d\r\n", QL_SIM_READ_RECORD, QL_SIM_EF_MSISDN, QL_SIM_READ_P1, QL_SIM_READ_P2, QL_SIM_READ_LEN); ret = ql_atcmd_send_sync(atcmd, resp, sizeof(resp), NULL,5); if(ret==QL_AT_RESP_OK) { //sim_log("%s at resp : %s\r\n", __func__, resp); len = ql_atcmd_get_para_value_str(resp, 0, 2, para, sizeof(para)); //find data area -TS 31.102 [4.2.26] /* EFMSISDN(6F40) 1 to X Alpha Identifier X+1 Length of BCD number/SSC contents X+2 TON and NPI X+3 to X+12 Dialling Number/SSC String X+13 Capability/Configuration2 Record Identifier X+14 Extension5 Record Identifier Example: 4D79204E756D626572FFFFFFFFFF07918123108845F8FFFFFFFFFFFF */ if((len % 2) || len < (14 * 2) || len >= sizeof(para)) { return QL_SIM_GENERIC_FAILURE; } praser = (ql_sim_ef_praser_t *)&(para[len]); praser -= 14; header = (ql_sim_ef_header_t *)praser; sim_log("%c,%c,%c,%c",header->bcd_len_l,header->bcd_len_h,header->ton_npi_l,header->ton_npi_h); /* BCD lengh. Max:11 = 14 - 2 - 1. */ len = ((((header->bcd_len_l - '0') & 0x0F) << 4)|((header->bcd_len_h - '0') & 0x0F)) << 1; sim_log("%s EF_MSISDN: %s/%d/%d\r\n", __func__, para,len,phonenumber_len); /* Check if buffer is overflow. */ if(len > (11 * 2) || len > phonenumber_len) { return QL_SIM_GENERIC_FAILURE; } if(header->ton_npi_l == '9' && header->ton_npi_h == '1'){ strcat(phonenumber, "+"); } praser += 2; //Jump length of BCD number/SSC contents/ & TON and NPI; len -= 2; do { memset(temp, 0, sizeof(temp)); if(praser->h_byte >= '0' && praser->h_byte <= '9'){ temp[0] = praser->h_byte; } if(praser->l_byte >= '0' && praser->l_byte <= '9'){ temp[1] = praser->l_byte; } strcat(phonenumber, temp); praser ++; i += 2; }while(i < len); sim_log("%s resp phonenumber: %s\r\n", __func__, phonenumber); } return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_verify_pin(QL_SIM_VERIFY_PIN_INFO *pt_info) // NOT SUPPORT { int ret = 0; char at_cmd_str[64]={0}; sprintf(at_cmd_str,"%s%s=%s%s",AT_CMD_PREFFIX,AT_CMD_NAME_CPIN,pt_info->pin_value,AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_change_pin(QL_SIM_CHANGE_PIN_INFO *pt_info ) // [IN] PIN { int ret = 0; char at_cmd_str[64]={0}; sprintf(at_cmd_str,"%s%s=SC,%s,%s%s",AT_CMD_PREFFIX,AT_CMD_NAME_CPWD,pt_info->old_pin_value,pt_info->new_pin_value,AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_unblock_pin(QL_SIM_UNBLOCK_PIN_INFO *pt_info)// [IN] input PUK/PUK2 and new PIN/PIN2 { int ret = 0; char at_cmd_str[64]={0}; sprintf(at_cmd_str,"%s%s=%s,%s%s",AT_CMD_PREFFIX,AT_CMD_NAME_CPIN,pt_info->puk_value,pt_info->new_pin_value,AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_enable_pin(QL_SIM_VERIFY_PIN_INFO *pt_info)// [IN] PIN { int ret = 0; char at_cmd_str[64]={0}; char get_pin_value_temp[64]={0}; sprintf(at_cmd_str,"%s%s=SC,1,%s%s",AT_CMD_PREFFIX,AT_CMD_NAME_CLCK,pt_info->pin_value, AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_disable_pin(QL_SIM_VERIFY_PIN_INFO *pt_info ) // [IN] PIN { int ret = 0; char at_cmd_str[64]={0}; sprintf(at_cmd_str,"%s%s=SC,0,%s%s",AT_CMD_PREFFIX,AT_CMD_NAME_CLCK,pt_info->pin_value, AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } //获取当前主卡的状态 QL_SIM_ERROR_CODE ql_sim_get_card_status(int *card_status) { //Modified by freddy@20200907 双卡时需要根据当前卡号来获取状态 #if defined(QUEC_DUAL_SIM_SUPPORT) && !defined(NO_DIALER) //Added by freddy @20201022 切卡中卡状态直接返回unknown extern SimSwitchCtx gCmSimSwitchCtx; SimSwitchCtx *ctx = &gCmSimSwitchCtx; if (ctx->state != CM_SIM_SWITCH_INIT) { *card_status=QL_SIM_STATUS_UNKNOWN; return QL_SIM_SUCCESS; } switch ( isMasterSim0() ? gSimPinState : gSimPinState_1) #else switch ( gSimPinState ) #endif { case CI_SIM_PIN_ST_READY: //Modified by freddy@20200907 双卡时需要根据当前卡号来获取状态 #ifdef QUEC_DUAL_SIM_SUPPORT if (( isMasterSim0() ? gSimStatus : gSimStatus_1) == CI_SIM_ST_READY) #else if (gSimStatus == CI_SIM_ST_READY) #endif { *card_status=QL_SIM_STATUS_READY; } break; case CI_SIM_PIN_ST_UNIVERSALPIN_REQUIRED: case CI_SIM_PIN_ST_CHV1_REQUIRED: *card_status=QL_SIM_STATUS_SIM_PIN; break; case CI_SIM_PIN_ST_CHV2_REQUIRED: *card_status=QL_SIM_STATUS_SIM_PIN2; break; case CI_SIM_PIN_ST_UNBLOCK_UNIVERSALPIN_REQUIRED: case CI_SIM_PIN_ST_UNBLOCK_CHV1_REQUIRED: *card_status=QL_SIM_STATUS_SIM_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_CHV2_REQUIRED: *card_status=QL_SIM_STATUS_SIM_PUK2; break; case CI_SIM_PIN_ST_HIDDENKEY_REQUIRED: *card_status=QL_SIM_STATUS_PH_FSIM_PIN; break; case CI_SIM_PIN_ST_UNBLOCK_HIDDENKEY_REQUIRED: *card_status=QL_SIM_STATUS_PH_FSIM_PUK; break; case CI_SIM_PIN_ST_PCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_SIM_LOCK_PIN; break; case CI_SIM_PIN_ST_NCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_NET_PIN; break; case CI_SIM_PIN_ST_NSCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_NET_SUB_PIN; break; case CI_SIM_PIN_ST_SPCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_SP_PIN; break; case CI_SIM_PIN_ST_CCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_CORP_PIN; break; case CI_SIM_PIN_ST_UNBLOCK_PCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_SIM_LOCK_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_NCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_NET_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_NSCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_NET_SUB_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_SPCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_SP_PUK; break; case CI_SIM_PIN_ST_UNBLOCK_CCK_REQUIRED: *card_status=QL_SIM_STATUS_PH_CORP_PUK; break; case CI_SIM_PIN_ST_CHV1_BLOCKED: case CI_SIM_PIN_ST_CHV2_BLOCKED: case CI_SIM_PIN_ST_UNIVERSALPIN_BLOCKED: case CI_SIM_PIN_ST_UNBLOCK_CHV1_BLOCKED: case CI_SIM_PIN_ST_UNBLOCK_CHV2_BLOCKED: case CI_SIM_PIN_ST_UNBLOCK_UNIVERSALPIN_BLOCKED: *card_status=QL_SIM_STATUS_BLOCKED; break; case CI_SIM_PIN_ST_REMOVED: *card_status=QL_SIM_STATUS_NOT_INSERTED; break; case CI_SIM_PIN_ST_WAIT_INITIALISATION: *card_status=QL_SIM_STATUS_BUSY; break; case CI_SIM_PIN_ST_NETWORK_REJECTED: //Modified by freddy@20200907 双卡时需要根据当前卡号来获取状态 #ifdef QUEC_DUAL_SIM_SUPPORT if (( isMasterSim0() ? gSimStatus : gSimStatus_1) == CI_SIM_ST_READY) #else if (gSimStatus == CI_SIM_ST_READY) #endif { *card_status=QL_SIM_STATUS_READY; } else { *card_status=QL_SIM_STATUS_UNKNOWN; } break; case CI_SIM_PIN_ST_MEP_ERROR: case CI_SIM_PIN_ST_UDP_ERROR: case CI_SIM_PIN_ST_CPHS_ERROR: case CI_SIM_PIN_ST_INIT_FAILED: case CI_SIM_PIN_ST_GENERAL_ERROR: default: *card_status=QL_SIM_STATUS_UNKNOWN; break; } return QL_SIM_SUCCESS; } QL_SIM_ERROR_CODE ql_sim_get_file_info ( unsigned int fileid, QL_SIM_FILE_INFO *file_info, // [OUT] output file info QL_SIM_FILE_OPERATION_RET *operation_ret // [OUT] return the operation status code ) { return QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_read_file ( unsigned int fileid, // EF file id unsigned int index, // the index of record for a record EF file, the offest of date for a transparent EF file. unsigned int data_max_len, // the max length of output data. QL_SIM_CARD_FILE_DATA *file_data, // [OUT] File data QL_SIM_FILE_OPERATION_RET *operation_ret // [OUT] return the operation status code ) { return QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_write_file ( unsigned int fileid, // EF file id int index, // the index of record for a record EF file, the offest of date for a transparent EF file. QL_SIM_CARD_FILE_DATA *file_data, ///< [IN] File data of the specified one by pt_info QL_SIM_FILE_OPERATION_RET *operation_ret // [OUT] return the operation status code ) { return QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_read_phonebook_record ( QL_SIM_PHONE_BOOK_STORAGE storage, //IN the storage position of the phone book int start_index, int end_index, char *username, QL_SIM_PHONE_BOOK_RECORDS_INFO *records // the list of records ) { int ret = 0,j=0; char resp[1024]={0}; char para[64]={0}; char encode[16]={0}; char at_cmd_str[64]={0}; memset(records,0,sizeof(QL_SIM_PHONE_BOOK_RECORDS_INFO)); ret = ql_atcmd_send_sync("AT+CSCS?\r\n",resp,sizeof(resp),NULL,5); if(ret==QL_AT_RESP_OK) { ql_atcmd_get_para_value_str(resp,0,0,encode,sizeof(encode)); if(strcmp(encode,"UCS2")) snprintf(at_cmd_str,sizeof(at_cmd_str),"AT+CSCS=UCS2;+CPBS=%s\r\n",QL_SIM_PHONE_BOOK_STORAGE_STR[storage]); else snprintf(at_cmd_str,sizeof(at_cmd_str),"AT+CPBS=%s\r\n",QL_SIM_PHONE_BOOK_STORAGE_STR[storage]); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); if(ret==QL_AT_RESP_OK) { if((start_index!=0)&&(end_index>=start_index)&&((end_index-start_index)0) { line_num--; ql_atcmd_get_para_value_str(resp,line_num,0, para,sizeof(para)); records->record[line_num].index=atoi(para); ql_atcmd_get_para_value_str(resp,line_num,2, para,sizeof(para)); strncpy((char *)(records->record[line_num].phonenum),para,24); ql_atcmd_get_para_value_str(resp,line_num,4, para,sizeof(para)); unsigned int *usc2_data=(unsigned int *)calloc(strlen(para)/4,sizeof(unsigned int)); if(usc2_data) { for(j=0;j<(strlen(para)/4);j++) { char tmp[5]={0}; strncpy(tmp,para+j*4,4); sscanf(tmp,"%x",&usc2_data[j]); } quec_usc2_to_utf8(usc2_data,j,records->record[line_num].username); free(usc2_data); } records->record_count++; } } } } if(strcmp(encode,"UCS2")) { snprintf(at_cmd_str,sizeof(at_cmd_str),"AT+CSCS=%s\r\n",encode); ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); } return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_write_phonebook_record ( QL_SIM_PHONE_BOOK_STORAGE storage, //IN the storage position of the phone book QL_SIM_PHONE_BOOK_RECORD_INFO *record //IN a record ) { int ret = 0; char resp[64]={0}; char para[64]={0}; char encode[16]={0}; char at_cmd_str[1024]={0}; ret = ql_atcmd_send_sync("AT+CSCS?\r\n",resp,sizeof(resp),NULL,5); if(ret==QL_AT_RESP_OK) { ql_atcmd_get_para_value_str(resp,0,0,encode,sizeof(encode)); if(strcmp(encode,"UCS2")) snprintf(at_cmd_str,sizeof(at_cmd_str),"AT+CSCS=UCS2;+CPBS=%s\r\n",QL_SIM_PHONE_BOOK_STORAGE_STR[storage]); else snprintf(at_cmd_str,sizeof(at_cmd_str),"AT+CPBS=%s\r\n",QL_SIM_PHONE_BOOK_STORAGE_STR[storage]); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); if(ret==QL_AT_RESP_OK) { if(strlen((char *)(record->phonenum))>0) { if(record->index!=0) snprintf(at_cmd_str,sizeof(at_cmd_str),"AT+CPBW=%d,%s,129,",record->index,record->phonenum); else snprintf(at_cmd_str,sizeof(at_cmd_str),"AT+CPBW=,%s,129,",record->phonenum); int i=0; int num=quec_utf8_to_usc2(record->username,strlen((char *)(record->username)),NULL); unsigned int *username_usc2=(unsigned int *)calloc(num,sizeof(unsigned int)); if(username_usc2) { quec_utf8_to_usc2(record->username,strlen((char *)(record->username)),username_usc2); for(i=0;iindex!=0) snprintf(at_cmd_str,sizeof(at_cmd_str),"AT+CPBW=%d\r\n",record->index); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); } } if(strcmp(encode,"UCS2")) { snprintf(at_cmd_str,sizeof(at_cmd_str),"AT+CSCS=%s\r\n",encode); ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,5); } return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } /* 2023 03 16 ql sim detect support */ extern UINT32 usim_1_detect_gpio; extern UINT32 usim_1_detect_gpio_insert_level; extern void usim_init_hook(USIM_Card card); #if defined (__QUECTEL_PROJECT_EC600KCN_CC__) || defined (__QUECTEL_PROJECT_EC600KCN_LC__) || defined (__QUECTEL_PROJECT_EC600KCN_LK__) || defined (__QUECTEL_PROJECT_EC600KCN_CK__) #define QUEC_USIM1_DET_PIN GPIO_PIN_NO_85 //this consider you project #else #define QUEC_USIM1_DET_PIN GPIO_PIN_49 //this consider you project #endif typedef struct { unsigned char init; unsigned char detenable; PIN_LEVEL_E insertlevel; sim_detect_calback callback; unsigned int detect_gpio; }ql_sim_detect_s,*ql_sim_detect_p; ql_sim_detect_s g_sim_detect = {0}; unsigned char ql_sim1_detect_is_enable(void) { ql_sim_detect_p sim_detect_p = &g_sim_detect; return (sim_detect_p->detenable)?(true):(false); } void ql_sim1_detect_ind_cust_callback(unsigned int insert_status) { ql_sim_detect_p sim_detect_p = &g_sim_detect; PIN_LEVEL_E pin_level = PIN_LEVEL_LOW; if(insert_status){ pin_level = sim_detect_p->insertlevel; }else{ pin_level = (PIN_LEVEL_E)(!sim_detect_p->insertlevel); } if(sim_detect_p->callback){ sim_detect_p->callback(pin_level); } } QL_SIM_ERROR_CODE ql_sim1_detect_gpio_config(unsigned int detect_gpio) { ql_sim_detect_p sim_detect_p = &g_sim_detect; //CPUartLogPrint("ql_sim1_detect_gpio_config",1); sim_log("%s detect_gpio=%d \r\n", __func__, detect_gpio); sim_detect_p->detect_gpio = detect_gpio; usim_1_detect_gpio = sim_detect_p->detect_gpio; return QL_SIM_SUCCESS; } QL_SIM_ERROR_CODE ql_sim_config_hot_plug_detect(unsigned char detenable, PIN_LEVEL_E insertlevel,sim_detect_calback detectcallback) { ql_sim_detect_p sim_detect_p = &g_sim_detect; if(detectcallback == NULL){ sim_log("%s ptr error!\r\n",__func__); return QL_SIM_GENERIC_FAILURE; } //CPUartLogPrint("ql_sim_config_hot_plug_detect",1); sim_log("%s enable=%d, insert_level=%d, callback=0x%x detect_gpio=%d\r\n", __func__, detenable, insertlevel, detectcallback, sim_detect_p->detect_gpio); sim_detect_p->callback = detectcallback; sim_detect_p->detenable = detenable; sim_detect_p->insertlevel = insertlevel; // sim1 config for low level init. if(sim_detect_p->detect_gpio != 0){ usim_1_detect_gpio = sim_detect_p->detect_gpio;//user config sim detect pin }else{ usim_1_detect_gpio = QUEC_USIM1_DET_PIN; } usim_1_detect_gpio_insert_level = insertlevel; if(true != sim_detect_p->init){ usim_init_hook(USIM_COM_CARD); sim_detect_p->init = true; } return QL_SIM_SUCCESS; } QL_SIM_ERROR_CODE ql_sim_open_logical_channel(char *dfName, UINT16* sessionId) { int ret = 0; char at_cmd_str[128]={0}; char resp[64]={0}; char para[64]={0}; if((dfName == NULL) || (sessionId == NULL)) { return QL_SIM_GENERIC_FAILURE; } snprintf(at_cmd_str,sizeof(at_cmd_str)-1,"%s%s=%s%s",AT_CMD_PREFFIX,AT_CMD_NAME_CCHO,dfName,AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,resp,sizeof(resp),NULL,10); if(ret==QL_AT_RESP_OK) { ql_atcmd_get_para_value_str(resp,0,0,para,sizeof(para)); *sessionId=atoi(para); } return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_close_logical_channel(UINT16 sessionId) { int ret = 0; char at_cmd_str[64]={0}; char resp[64]={0}; char para[64]={0}; snprintf(at_cmd_str,sizeof(at_cmd_str)-1,"%s%s=%d%s",AT_CMD_PREFFIX,AT_CMD_NAME_CCHC,sessionId,AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,NULL,0,NULL,10); return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; } QL_SIM_ERROR_CODE ql_sim_access_logical_channel(UINT16 sessionId, UINT16 commandlength, char *command, UINT16* resplength, char *response) { int ret = 0; char at_cmd_str[1024]={0}; char resp[512]={0}; char para[512]={0}; if((resplength == NULL) || (response == NULL)) { return QL_SIM_GENERIC_FAILURE; } snprintf(at_cmd_str,sizeof(at_cmd_str)-1,"%s%s=%d,%d,%s%s",AT_CMD_PREFFIX,AT_CMD_NAME_CGLA,sessionId,commandlength,command,AT_CMD_SUFFIX); ret = ql_atcmd_send_sync(at_cmd_str,resp,sizeof(resp),NULL,10); if(ret==QL_AT_RESP_OK) { ql_atcmd_get_para_value_str(resp,0,0,para,sizeof(para)); *resplength=atoi(para); memset(para,0,sizeof(para)); ql_atcmd_get_para_value_str(resp,0,1,para,sizeof(para)); memcpy(response,para,strlen(para)); } return (ret==QL_AT_RESP_OK)?QL_SIM_SUCCESS:QL_SIM_GENERIC_FAILURE; }