补充文件
authorp15692025051 <846603105@qq.com>
Tue, 11 Mar 2025 10:01:45 +0000 (18:01 +0800)
committerp15692025051 <846603105@qq.com>
Tue, 11 Mar 2025 10:01:45 +0000 (18:01 +0800)
25 files changed:
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/audio_handle.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/audio_handle.h [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/jrtc.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modG722.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modalipay_collection.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modalipay_se.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modecdh.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modecdsa.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modipsec.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modjrtc_test.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modlvgl_other_hander.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modlvgl_other_hander.h [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modnfc.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modsftp.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modsif.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modstk.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modussd.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modvoip.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modwifi.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modwifi.h [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/nfc_sl6320.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/sensor_VC9202.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/sim_esim_ipa.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/tp_ft6x36.c [new file with mode: 0644]
2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/tp_st1615.c [new file with mode: 0644]

diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/audio_handle.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/audio_handle.c
new file mode 100644 (file)
index 0000000..5d1be36
--- /dev/null
@@ -0,0 +1,956 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include "runtime.h"
+#if MICROPY_QPY_AUDIO_AUDIO
+#include <string.h>
+#include "helios_debug.h"
+#include "audio_queue.h"
+#include "helios_fs.h"
+#include "helios_audio.h"
+#include "helios_os.h"
+
+#define HELIOS_AUDIO_LOG(fmt, ...) custom_log(audio_audio, fmt, ##__VA_ARGS__)
+
+
+typedef enum{
+       AUD_STREAM_FORMAT_MP3 = 0,
+       AUD_STREAM_FORMAT_AMR = 1,
+       AUD_STREAM_FORMAT_PCM = 2,
+       AUD_STREAM_FORMAT_AMRNB,
+       AUD_STREAM_FORMAT_AMRWB,
+       AUD_STREAM_FORMAT_SND,
+       AUD_STREAM_FORMAT_END
+}aud_stream_format;
+
+c_callback_t *g_audio_callback;
+/*=============================================================================*/
+/* FUNCTION: audio_play_callback                                               */
+/*=============================================================================*/
+/*!@brief              : callback function for audio file playing.
+ * @param[in]  : state - audio state
+ * @param[out]         : 
+ * @return             :
+ */
+/*=============================================================================*/
+int audio_play_callback(char *ptr, size_t lens, Helios_EnumAudPlayerState state)
+{
+       int audio_event = state;
+       Helios_Mutex_Lock(audio.queue_mutex, HELIOS_WAIT_FOREVER);
+       uint8_t audio_state = audio.audio_state;
+       Helios_Mutex_Unlock(audio.queue_mutex);
+       HELIOS_AUDIO_LOG("[Audio] callback, event = %d\r\n", state);
+
+
+       switch (state)
+       {
+       case HELIOS_AUD_PLAYER_FINISHED:
+               audio_event = 7;
+       break;
+       case HELIOS_AUD_PLAYER_CLOSE:
+               audio_event = 7;
+               state = HELIOS_AUD_PLAYER_FINISHED;
+       break;
+       case HELIOS_AUD_PLAYER_NODATA_STRAT:
+               audio_event = 5;
+       break;
+       case HELIOS_AUD_PLAYER_DATA_RESUME:
+               audio_event = 6;
+       break;
+       default:
+               break;
+       }
+               
+       if ((g_audio_callback != NULL) /*&& (audio_state != AUDIO_IDLE)*/)
+       {
+               HELIOS_AUDIO_LOG("[Audio] callback start.\r\n");
+               GC_STACKTOP_SET();
+               mp_sched_schedule_ex(g_audio_callback, mp_obj_new_int(audio_event));
+               GC_STACKTOP_CLEAR();
+               HELIOS_AUDIO_LOG("[Audio] callback end.\r\n");
+       }
+
+       switch (state)
+       {
+               case HELIOS_AUD_PLAYER_START:
+               case HELIOS_AUD_PLAYER_RESUME:
+                       Helios_Mutex_Lock(audio.queue_mutex, HELIOS_WAIT_FOREVER);
+                       audio.audio_state = AUDIO_PLAYING;
+                       Helios_Mutex_Unlock(audio.queue_mutex);
+                       break;
+               case HELIOS_AUD_PLAYER_FINISHED:
+                       Helios_Mutex_Lock(audio.queue_mutex, HELIOS_WAIT_FOREVER);
+                       audio.audio_state = AUDIO_IDLE;
+                       Helios_Mutex_Unlock(audio.queue_mutex);
+                       uint8_t audio_msg = AUDIO_FINISH_EVENT;
+                       if (audio.montage_is_stopping == 0) {
+                               if (Helios_MsgQ_Put(audio.queue_msg, (const void *)&audio_msg, sizeof(uint8_t), HELIOS_NO_WAIT) == -1)
+                               {
+                                       HELIOS_AUDIO_LOG("send audio msg failed[%u].\r\n", audio_msg);
+                                       return -1;
+                               }
+                       }
+                       HELIOS_AUDIO_LOG("send audio finished signal successed[%u].\r\n", audio_msg);
+                       break;
+               case HELIOS_AUD_PLAYER_ERROR:
+               case HELIOS_AUD_PLAYER_PAUSE:
+               case HELIOS_AUD_PLAYER_CLOSE:
+                       Helios_Mutex_Lock(audio.queue_mutex, HELIOS_WAIT_FOREVER);
+                       audio.audio_state = AUDIO_IDLE;
+                       Helios_Mutex_Unlock(audio.queue_mutex);
+                       break;
+               default:
+                       break;
+       }
+       return 0;
+}
+
+
+
+int audio_err_handle(void)
+{
+       //return 0;
+    if ((g_audio_callback != NULL) /*&& (audio_state != AUDIO_IDLE)*/)
+    {
+        HELIOS_AUDIO_LOG("[Audio] callback start.\r\n");
+        GC_STACKTOP_SET();
+        mp_sched_schedule_ex(g_audio_callback, mp_obj_new_int(8));
+        GC_STACKTOP_CLEAR();
+        HELIOS_AUDIO_LOG("[Audio] callback end.\r\n");
+    }
+    Helios_Mutex_Lock(audio.queue_mutex, HELIOS_WAIT_FOREVER);
+    audio.audio_state = AUDIO_IDLE;
+    Helios_Mutex_Unlock(audio.queue_mutex);
+    uint8_t audio_msg = AUDIO_FINISH_EVENT;
+    if (audio.montage_is_stopping == 0) {
+               if (Helios_MsgQ_Put(audio.queue_msg, (const void *)&audio_msg, sizeof(uint8_t), HELIOS_NO_WAIT) == -1)
+               {
+                       HELIOS_AUDIO_LOG("send audio msg failed[%u].\r\n", audio_msg);
+                       return -1;
+               }
+       }
+    HELIOS_AUDIO_LOG("send audio finished signal successed[%u].\r\n", audio_msg);
+    return 0;
+}
+
+
+
+
+
+
+
+
+#if !CONFIG_AUDIO
+
+#define MONTAGE_LEN 2048
+#define MONTAGE_FLAGE_LEN 8
+#define MONTAGE_MAX_NUMBER 16
+#define MONTAGE_IDENTIFICATION "montage"
+#define ARRAY_IS_USED 1
+#define ARRAY_NOT_USED 0
+
+#define FREE_BUFF(X) do \
+{                       \
+    if(X) {             \
+        free(X);        \
+        X = NULL;       \
+    }                   \
+} while (0);   
+
+
+#define CALLOC_BUFF_SET(X,Y) do     \
+{                                   \
+    X = calloc(1, strlen(Y)+16);       \
+    memset(X, 0, strlen(Y)+16);      \
+    if(X) {                         \
+        strncpy(X, Y, strlen(Y));   \
+    }                               \
+} while (0);
+
+
+Helios_Thread_t montage_play_task_id = 0;
+Helios_MsgQ_t montage_play_queue = 0;
+static char montage_is_break = 0;
+
+typedef struct
+{
+    char* montage_name;
+    char* file_name;
+    Helios_AudPlayerType type;
+    Helios_AudOutputType outputtype;
+    helios_cb_on_player usr_cb;
+} montage_play_elem;
+
+typedef struct
+{
+    char file_name[128];
+    uint32_t offset;
+    uint32_t size;
+} montage_elem;
+
+typedef struct
+{
+    char is_used;
+    char montage_name[128];
+    uint32_t file_num;
+    montage_elem *file_info_buf;
+} montage_info;
+
+enum
+{
+    PLAY_MOREFILES_ERR_OK = 0,
+    PLAY_MOREFILES_ERR_SINGLEFILE = -1,
+    PLAY_MOREFILES_ERR_FILENOTEXIST = -2,
+    PLAY_MOREFILES_ERR_FILENFSFAIL = -3,
+};
+
+int helios_set_montage_break_flag(char set) {
+       if(set == 1 || set == 0)
+       {
+               montage_is_break = set;
+               return 0;
+       }
+       return -1;
+}
+
+static montage_info all_montage[MONTAGE_MAX_NUMBER] = {0};
+
+// Check whether it has been preprocessed
+// Check for preprocessing
+static char __check_is_preprocessed(char *montage_name)
+{
+    int i = 0;
+    char ret = -1;
+
+    for (i = 0; i < MONTAGE_MAX_NUMBER; i++)
+    {
+        if (all_montage[i].is_used == ARRAY_IS_USED && (0 == strncmp(all_montage[i].montage_name, montage_name, strlen(montage_name))))
+        {
+            ret = i;
+            break;
+        }
+    }
+    return ret;
+}
+
+// Gets a free preprocessed array
+static char __Get_idle_preprocessing_array()
+{
+    int i = 0;
+    char ret = -1;
+
+    for (i = 0; i < MONTAGE_MAX_NUMBER; i++)
+    {
+        if (all_montage[i].is_used == ARRAY_NOT_USED)
+        {
+            ret = i;
+            break;
+        }
+    }
+    return ret;
+}
+
+//Pretreatment process
+//Preprocessing process
+static char montage_file_preprocessing(char *montage_name)
+{
+    char montage_buf[MONTAGE_FLAGE_LEN + 1] = {0};
+    char NumberOfFilesBuff[4] = {0};
+    uint32_t Number_of_files = 0;
+    montage_elem *file_information = NULL;
+    montage_info *ret = NULL;
+    int8_t idle_index = -1;
+    int8_t montage_index = -1;
+
+    montage_index = __check_is_preprocessed(montage_name);
+    if (montage_index != -1)
+    {
+        return montage_index;
+    }
+
+    idle_index = __Get_idle_preprocessing_array();
+    if (idle_index == -1)
+    {
+        HELIOS_AUDIO_LOG("No idle preprocessing array");
+        return -1;
+    }
+
+    HeliosFILE *fp = Helios_fopen(montage_name, "rb");
+    if (NULL == fp)
+    {
+        HELIOS_AUDIO_LOG("montage(%s) open fail\n", montage_name);
+        idle_index = -1;
+        goto err;
+    }
+
+    // Check document identification
+    if (MONTAGE_FLAGE_LEN != Helios_fread(&montage_buf, 1, MONTAGE_FLAGE_LEN, fp))
+    {
+        HELIOS_AUDIO_LOG("montage read identification fail\n");
+        idle_index = -1;
+        goto err;
+    }
+
+    if (0 != strncmp(montage_buf, MONTAGE_IDENTIFICATION, MONTAGE_FLAGE_LEN))
+    {
+        HELIOS_AUDIO_LOG("This file is not a splice file\n");
+        idle_index = -1;
+        goto err;
+    }
+
+    // Get number of files
+    if (4 != Helios_fread(&NumberOfFilesBuff, 4, 1, fp))
+    {
+        HELIOS_AUDIO_LOG("Failed to read the number of files\n");
+        idle_index = -1;
+        goto err;
+    }
+
+    Number_of_files = *(uint32_t *)NumberOfFilesBuff;
+    HELIOS_AUDIO_LOG("The number of documents is %d\n", Number_of_files);
+    if (0 == Number_of_files)
+    {
+        idle_index = -1;
+        goto err;
+    }
+
+    // Application buf save header
+    file_information = calloc(Number_of_files, sizeof(montage_elem));
+    if (NULL == file_information)
+    {
+        HELIOS_AUDIO_LOG("File information memory request failed\n");
+        idle_index = -1;
+        goto err;
+    }
+
+    int aa_debug = Helios_fread((void *)file_information, (Number_of_files * sizeof(montage_elem)), 1, fp);
+    HELIOS_AUDIO_LOG("read size= %d, actual = %d\n", Number_of_files * sizeof(montage_elem), aa_debug);
+    if ((int)(Number_of_files * sizeof(montage_elem)) != aa_debug)
+    {
+        HELIOS_AUDIO_LOG("Failed to read file information\n");
+        if (file_information)
+        {
+            free(file_information);
+            file_information = NULL;
+        }
+        return -1;
+    }
+    all_montage[idle_index].is_used = ARRAY_IS_USED;
+    memcpy(&(all_montage[idle_index].montage_name), montage_name, strlen(montage_name));
+    all_montage[idle_index].file_num = Number_of_files;
+    all_montage[idle_index].file_info_buf = file_information;
+
+err:
+    if (fp)
+    {
+        Helios_fclose(fp);
+        fp = NULL;
+    }
+
+    return idle_index;
+}
+
+// Gets the file information in the stitched file
+static montage_elem *__getElemByName(char *montage_name, char *file_name)
+{
+    int8_t montage_index = -1;
+    int8_t elem_index = -1;
+    montage_elem *elem = NULL;
+    char actual_name[128] = {0};
+
+    montage_index = montage_file_preprocessing(montage_name);
+    if (-1 == montage_index)
+    {
+        return NULL;
+    }
+    elem = (montage_elem *)(all_montage[montage_index].file_info_buf);
+
+    sprintf(actual_name, file_name + 3, strlen(file_name) - 3);
+
+    uint32_t i = 0;
+    for (i = 0; i < all_montage[montage_index].file_num; i++)
+    {
+        if (0 == strncmp(file_name, elem->file_name, strlen(actual_name)+3))
+        {
+            return elem;
+        }
+        elem++;
+    }
+
+    return NULL;
+}
+
+Helios_AudStreamFormat auStreamFormatBySuffix(const char *fname)
+{
+    if (fname == NULL)
+        return HELIOS_AUDIO_FORMAT_UNKNOWN;
+
+    char *dot = strrchr(fname, '.');
+    if (dot == NULL)
+        return HELIOS_AUDIO_FORMAT_AMRNB;
+
+    if (strcasecmp(dot, ".pcm") == 0)
+        return HELIOS_AUDIO_FORMAT_PCM;
+
+    if (strcasecmp(dot, ".wav") == 0)
+        return HELIOS_AUDIO_FORMAT_WAVPCM;
+
+    if (strcasecmp(dot, ".mp3") == 0)
+        return HELIOS_AUDIO_FORMAT_MP3;
+
+    if (strcasecmp(dot, ".amr") == 0)
+        return HELIOS_AUDIO_FORMAT_AMRNB;
+
+    if (strcasecmp(dot, ".awb") == 0)
+        return HELIOS_AUDIO_FORMAT_AMRWB;
+
+    return HELIOS_AUDIO_FORMAT_UNKNOWN;
+}
+
+static int is_play = 0;
+struct mp3_file_list
+{
+    montage_elem *elem;
+    char file_name[128];
+    struct mp3_file_list *next;
+};
+static void mp3_file_list_push(struct mp3_file_list *head, struct mp3_file_list *item)
+{
+    struct mp3_file_list *p = NULL;
+    if (head == NULL)
+    {
+        return;
+    }
+    p = head;
+    while (p->next != NULL)
+    {
+        p = p->next;
+    }
+
+    p->next = item;
+}
+
+static struct mp3_file_list *mp3_file_list_pop(struct mp3_file_list *head)
+{
+    struct mp3_file_list *p = NULL;
+    if (head == NULL)
+    {
+        return NULL;
+    }
+
+    if (head->next)
+    {
+        p = head->next;
+        head->next = p->next;
+        return p;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+static void mp3_file_list_destroy(struct mp3_file_list *head)
+{
+    if (head == NULL)
+    {
+        return;
+    }
+    do
+    {
+        struct mp3_file_list *item = mp3_file_list_pop(head);
+               if(item == NULL) {
+                       break;
+               }
+        FREE_BUFF(item);
+    }while (head->next != NULL);
+
+}
+
+static int ql_audio_play_morefiles(char *montage_file, char *files, montage_play_elem *play_elem)
+{
+    struct mp3_file_list list_head = {.next = NULL};
+    char *path_dir = NULL;
+    char *p = NULL;
+    int total_files_size = 0;
+    int data_size = 0;
+    char *data = NULL;
+    char *files_tmp = NULL;
+    // char file_type = 0;
+    char tmp[128] = {0};
+    HeliosFILE *fp = NULL;
+    int result_ret = PLAY_MOREFILES_ERR_OK;
+    int file_cnt = 0;
+    montage_elem *elem = NULL;
+    void *elem_buf = NULL;
+    uint32_t count = 0;
+    int ret = 0;
+    int format = 0;
+    uint32_t cur_count = 0;
+    montage_is_break = 0;
+
+   uint32_t  cur_count_offset = 0;
+   uint32_t cur_count_size = 0;
+
+    if (strncmp(files, "mp3files=", 9) == 0)
+    {
+        // file_type = 1;
+    }
+    else if (strncmp(files, "amrfiles=", 9) == 0)
+    {
+        // file_type = 3;
+    }
+    else
+    {
+        /* not continue play */
+        result_ret = PLAY_MOREFILES_ERR_SINGLEFILE;
+        goto err2;
+    }
+
+    files_tmp = malloc(strlen(files) + 1);
+    memset(files_tmp, 0, strlen(files) + 1);
+    strcpy(files_tmp, files);
+
+    /* parse files info */
+    p = strtok(files_tmp + 9, "+");
+    if (p != NULL)
+    {
+        HELIOS_AUDIO_LOG("p = %s\n", p);
+    }
+    else
+    {
+        result_ret = PLAY_MOREFILES_ERR_FILENOTEXIST;
+        goto err2;
+    }
+
+    while (p != NULL)
+    {
+        struct mp3_file_list *item = NULL;
+        elem = __getElemByName(montage_file, p);
+        if (elem != NULL)
+        {
+            //HELIOS_AUDIO_LOG("XXX elem:%s, offset %d, size=%d\n", elem->file_name, elem->offset, elem->size);
+            item = calloc(1, sizeof(struct mp3_file_list));
+            sprintf(item->file_name, "%s", p);
+            item->elem = elem;
+            item->next = NULL;
+            mp3_file_list_push(&list_head, item);
+            file_cnt++;
+        }
+        else
+        {
+            while (list_head.next != NULL)
+            {
+                struct mp3_file_list *item = mp3_file_list_pop(&list_head);
+                if (item)
+                {
+                    free(item);
+                }
+            }
+            result_ret = PLAY_MOREFILES_ERR_FILENOTEXIST;
+            goto err2;
+        }
+        p = strtok(NULL, "+");
+    }
+
+
+    /* play files in once */
+    // data = malloc(total_files_size);
+    fp = Helios_fopen(montage_file, "rb");
+    if (NULL == fp)
+    {
+        result_ret = PLAY_MOREFILES_ERR_FILENOTEXIST;
+        goto err2;
+    }
+    elem_buf = (void *)calloc(1, MONTAGE_LEN);
+
+       do
+    {
+        struct mp3_file_list *item = mp3_file_list_pop(&list_head);
+               if(item == NULL) {
+                       break;
+               }
+
+        format = auStreamFormatBySuffix(item->elem->file_name);
+        HELIOS_AUDIO_LOG("format = %d\n", format);
+
+        if (item)
+        {
+            HELIOS_AUDIO_LOG("%s, offset %d, size=%d\n", item->elem->file_name, item->elem->offset, item->elem->size);
+
+            if((format == HELIOS_AUDIO_FORMAT_AMRNB) || (format == HELIOS_AUDIO_FORMAT_AMRWB)) {
+                cur_count_offset = item->elem->offset+6;
+                cur_count_size = item->elem->size - 6;
+            } else if(format == HELIOS_AUDIO_FORMAT_MP3){
+                               char mp3_head[10] = {0};
+                               int skip_size = 0;
+                               Helios_fseek(fp, item->elem->offset, SEEK_SET);
+                               Helios_fread(mp3_head, 1, 10, fp);
+                               if(mp3_head[0] == 73 && mp3_head[1] == 68 && mp3_head[2] == 51) {
+                                       skip_size = (mp3_head[6]&0x7F)*0x200000
+                                       +(mp3_head[7]&0x7F)*0x4000
+                                       +(mp3_head[8]&0x7F)*0x80
+                                       +(mp3_head[9]&0x7F) + 10;
+                                       HELIOS_AUDIO_LOG("is mp3 file, skip size[%d]\n", skip_size);
+                               }
+                cur_count_offset = item->elem->offset + skip_size;
+                cur_count_size = item->elem->size - skip_size;
+            } else {
+                cur_count_offset = item->elem->offset;
+                cur_count_size = item->elem->size;
+            }
+
+            ret = Helios_fseek(fp, cur_count_offset, SEEK_SET);
+            HELIOS_AUDIO_LOG("Helios_fseek = %d\n", ret);
+            if ((uint32_t)ret != cur_count_offset)
+            {
+                result_ret = PLAY_MOREFILES_ERR_FILENFSFAIL;
+                FREE_BUFF(item);
+                goto err2;
+            }
+
+            count = 0;
+
+            HELIOS_AUDIO_LOG("cur_count_size = %d\n", cur_count_size);
+            while (count < cur_count_size)
+            {
+                if (count + MONTAGE_LEN < cur_count_size)
+                {
+                    cur_count = Helios_fread(elem_buf, 1, MONTAGE_LEN, fp);
+                }
+                else
+                {
+                    cur_count = Helios_fread(elem_buf, 1, cur_count_size - count, fp);
+                }
+
+                HELIOS_AUDIO_LOG("cur_count = %d\n", cur_count);
+                if (cur_count <= 0)
+                    break;
+                count += cur_count;
+
+                HELIOS_AUDIO_LOG("format = %d, cur_count = %d, type = %d, outputtype = %d, usr_cb = 0x%x\n", format, cur_count, play_elem->type, play_elem->outputtype, play_elem->usr_cb);
+                               Helios_Mutex_Lock(audio.montage_mutex, HELIOS_WAIT_FOREVER);
+                ret = Helios_Audio_StreamPlayStart(format, elem_buf, cur_count, play_elem->type, play_elem->outputtype, audio_play_callback);
+                               if(ret != 0) {
+                                       HELIOS_AUDIO_LOG("old play stream ret : %d\n",  ret);
+                                       ret = Helios_Audio_StreamPlayStart(format, elem_buf, cur_count, play_elem->type, play_elem->outputtype, audio_play_callback);
+                                       HELIOS_AUDIO_LOG("again play stream ret : %d\n",  ret);
+                               }
+                               Helios_Mutex_Unlock(audio.montage_mutex);
+                Helios_msleep(100);
+                if (montage_is_break || (0 != ret))
+                {
+                    HELIOS_AUDIO_LOG("montage_is_break : %d ret : %d\n", montage_is_break, ret);
+                    #if !defined(PLAT_EIGEN) && !defined(PLAT_EIGEN_718)
+                    if(montage_is_break == 0) 
+                    {
+                                               audio_err_handle();
+                    }
+                    #endif
+
+                                       montage_is_break = 0;
+                    FREE_BUFF(item);
+                    goto err2;
+                }
+            }
+            FREE_BUFF(item);
+        }
+    }while (list_head.next != NULL);
+
+err2:
+
+    if (fp)
+    {
+        Helios_fclose(fp);
+        fp = NULL;
+    }
+
+    if (elem_buf)
+    {
+        free(elem_buf);
+        elem_buf = NULL;
+    }
+
+    if (files_tmp)
+    {
+        free(files_tmp);
+        files_tmp = NULL;
+    }
+
+    {
+        mp3_file_list_destroy(&list_head);
+    }
+
+    if(PLAY_MOREFILES_ERR_OK != result_ret) {
+        HELIOS_AUDIO_LOG("result_ret : %d \n", result_ret);
+        audio_err_handle();
+    }
+
+    return result_ret;
+}
+
+static void Helios_Montage_play_task(void *argv)
+{
+    (void)argv;
+    int ret = 0;
+    montage_play_elem play_elem;
+
+    while (1)
+    {
+        memset(&play_elem, 0, sizeof(montage_play_elem));
+
+        ret = Helios_MsgQ_Get(montage_play_queue, (void *)&play_elem, sizeof(montage_play_elem), HELIOS_WAIT_FOREVER);
+        if (ret != 0)
+        {
+            HELIOS_AUDIO_LOG("Splicing playback thread failed to get queue\n");
+            continue;
+        }
+        if (0 != ql_audio_play_morefiles(play_elem.montage_name, play_elem.file_name, &play_elem))
+        {
+            HELIOS_AUDIO_LOG("Failed to play montage audio\n");
+        }
+        FREE_BUFF(play_elem.montage_name);
+        FREE_BUFF(play_elem.file_name);
+    }
+}
+
+int Helios_Audio_MontageFilePlayStart(char *montage_name, char *file_name, Helios_AudPlayerType type, helios_cb_on_player usr_cb, uint8_t device)
+{
+
+    Helios_ThreadAttr attr = {0};
+    montage_play_elem play_elem;
+    if (0 == montage_play_queue)
+    {
+        montage_play_queue = Helios_MsgQ_Create(10, sizeof(montage_play_elem));
+        if (!montage_play_queue)
+        {
+            HELIOS_AUDIO_LOG("create montage queue failed, can not create msgQ.");
+            goto err1;
+        }
+    }
+
+    if (0 == montage_play_task_id)
+    {
+        attr.name = "audio_montage_play";
+        attr.stack_size = 4096;
+        attr.priority = 95;
+        attr.entry = Helios_Montage_play_task;
+
+        montage_play_task_id = Helios_Thread_Create(&attr);
+        if (0 == montage_play_task_id)
+        {
+            HELIOS_AUDIO_LOG("create montage task failed\n");
+            goto err1;
+        }
+    }
+
+    memset(&play_elem, 0, sizeof(montage_play_elem));
+
+    CALLOC_BUFF_SET(play_elem.montage_name, montage_name);
+    CALLOC_BUFF_SET(play_elem.file_name, file_name);
+
+    play_elem.outputtype = device;
+    play_elem.type = type;
+    play_elem.usr_cb = usr_cb;
+
+    if (montage_play_queue)
+    {
+               return Helios_MsgQ_Put(montage_play_queue, (const void *)&play_elem, sizeof(montage_play_elem), HELIOS_NO_WAIT);                
+    }
+
+    return 0;
+err1:
+    if (montage_play_queue)
+    {
+        Helios_MsgQ_Delete(montage_play_queue);
+        montage_play_queue = 0;
+    }
+
+    if (montage_play_task_id)
+    {
+        Helios_Thread_Delete(montage_play_task_id);
+        montage_play_task_id = 0;
+    }
+    return -1;
+}
+#endif
+
+
+
+#if defined (PLAT_Unisoc) || defined(PLAT_Unisoc_8910_R05) || defined(PLAT_Unisoc_8850_R02) || defined(PLAT_ASR_1606) || defined(PLAT_Unisoc_8910_R06)
+
+// 根据MPEG版本和Layer来定义比特率的查找表
+static int mp3_bitrates[2][3][16] = {
+    { // MPEG Version 1
+        {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, // Layer 1
+        {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0},    // Layer 2
+        {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}      // Layer 3
+    },
+    { // MPEG Version 2 & 2.5
+        {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0},    // Layer 1
+        {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0},         // Layer 2
+        {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}          // Layer 3
+    }
+};
+#define BUFFER_SIZE 1024
+
+// 每个编码模式下的帧长度(单位:字节),这个数组针对AMR-NB格式。对于AMR-WB,这些值会不同。
+static const int frameSize[16] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 5, 5, 5, 5, 5, 5, 0};
+
+static int get_file_size(char * file_name) {
+    HeliosFILE *fd = Helios_fopen(file_name, "rb");
+    if (!fd) {
+        perror("Unable to open file");
+        return 0.0;
+    }
+    Helios_fseek(fd, 0L, SEEK_END);
+    int file_size = Helios_ftell(fd);
+       Helios_fclose(fd);
+
+    return file_size;
+}
+ 
+static int check_audio_format_byFileName(const char *fname)
+{
+    if (fname == NULL)
+        return -1;
+
+    char *dot = strrchr(fname, '.');
+    if (dot == NULL)
+        return -1;
+
+    if (strcasecmp(dot, ".pcm") == 0)
+        return AUD_STREAM_FORMAT_PCM;
+
+    if (strcasecmp(dot, ".mp3") == 0)
+        return AUD_STREAM_FORMAT_MP3;
+
+    if (strcasecmp(dot, ".amr") == 0)
+        return AUD_STREAM_FORMAT_AMR;
+
+    return -1;
+}
+
+unsigned int syncsafe_to_int(unsigned char *bytes) {
+    return (bytes[0] << 21) | (bytes[1] << 14) | (bytes[2] << 7) | bytes[3];
+}
+
+int Helios_get_amr_file_time_lenth(char * file_name) {
+       HeliosFILE *fd = NULL;
+       int duration = 0;
+    unsigned char buffer[7] = {0};
+    int frame_size = 0;
+    int file_size = get_file_size(file_name);
+    fd = Helios_fopen(file_name, "rb");
+    if (!fd) {
+        HELIOS_AUDIO_LOG("Unable to open file\n");
+        return 0;
+    }
+    if (Helios_fread(buffer, 1, 7, fd) == 7) {
+        frame_size = frameSize[(buffer[6] >> 3) & 0x0F];
+        //HELIOS_AUDIO_LOG("frame_size = %d\n", frame_size);
+    }
+    duration = (file_size-6)/frame_size/50; // AMR一帧数据固定为20ms
+    Helios_fclose(fd);
+    return duration;
+}
+
+int Helios_get_mp3_file_time_lenth(char * file_name) {
+       HeliosFILE *fd = NULL;
+       unsigned char buffer[BUFFER_SIZE];
+       int duration = 0;
+    int file_size = get_file_size(file_name);
+       int bufferOffset = 0; // 缓冲区中的当前处理位置
+
+    fd = Helios_fopen(file_name, "rb");
+    if (!fd) {
+        HELIOS_AUDIO_LOG("Unable to open file\n");
+        return 0;
+    }
+    // Read the ID3v2 header
+    unsigned char header[10];
+    if (Helios_fread(header, 1, 10, fd) != 10) {
+        HELIOS_AUDIO_LOG("Error reading ID3v2 header\n");
+        Helios_fclose(fd);
+        return 0;
+    }
+
+    // Check if the file has an ID3v2 tag
+    if (header[0] == 'I' && header[1] == 'D' && header[2] == '3') {
+        // Calculate the tag size from the header
+        unsigned int tag_size = syncsafe_to_int(header + 6) + 10;
+        HELIOS_AUDIO_LOG("tag_size: %d\n", tag_size);
+        file_size = file_size - tag_size;
+        Helios_fseek(fd, tag_size, SEEK_SET);
+    } else {
+        // Not ID3v2 mp3 file seek file begin
+        Helios_fseek(fd, 0, SEEK_SET);
+    }
+
+    int frame_cnt = 0;
+    if (Helios_fread(buffer, 1, BUFFER_SIZE, fd) == BUFFER_SIZE) {
+        // 检查帧同步(11位全1)
+               while (bufferOffset < BUFFER_SIZE) {
+                       if ((buffer[bufferOffset] == 0xFF) && ((buffer[bufferOffset+1] & 0xE0) == 0xE0)) {
+                HELIOS_AUDIO_LOG("buffer[0]:%x, buffer[1]: %x, buffer[2]:%x, buffer[3]:%x\n", buffer[bufferOffset], buffer[bufferOffset+1], buffer[bufferOffset+2], buffer[bufferOffset+3]);
+                frame_cnt++;
+                if (frame_cnt > 0) {
+                    // 解析比特率和采样率
+                    int version = (buffer[bufferOffset+1] >> 3) & 0x03;
+                    int layer = (buffer[bufferOffset+1] >> 1) & 0x03;
+                    int bitrate_index = (buffer[bufferOffset+2] >> 4) & 0x0F;
+                    int bitrate = mp3_bitrates[0][2][bitrate_index] * 1000;
+                    duration = file_size * 8 / bitrate;
+                    HELIOS_AUDIO_LOG("version:%d, layer: %d, bitrate_index:%d, bitrate:%d\n", version, layer, bitrate_index, bitrate);
+                    break;
+                }
+               }
+                       bufferOffset++;
+               }
+    }
+
+    Helios_fclose(fd);
+    return duration; // 转换为秒
+}
+
+
+int Helios_get_audio_file_time_lenth(char * file_name) {
+       HeliosFILE *fd = Helios_fopen(file_name, "r");
+       if (fd == NULL) {
+               return 0;
+       }
+       int ret = check_audio_format_byFileName(file_name);
+       Helios_fclose(fd);
+
+       switch (ret)
+       {
+               case AUD_STREAM_FORMAT_MP3:
+                       return Helios_get_mp3_file_time_lenth(file_name);
+                       break;
+               case AUD_STREAM_FORMAT_PCM:
+                       return 0;
+                       break;
+               case AUD_STREAM_FORMAT_AMR:
+                       return Helios_get_amr_file_time_lenth(file_name);
+                       break;
+               default:
+                       return 0;
+       }
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/audio_handle.h b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/audio_handle.h
new file mode 100644 (file)
index 0000000..2f3f1cd
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AUDIO_HANDLE_H__
+#define __AUDIO_HANDLE_H__
+
+#include "helios_audio.h"
+
+
+int helios_set_montage_break_flag(char set);
+int Helios_get_audio_file_time_lenth(char * file_name);
+#endif 
\ No newline at end of file
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/jrtc.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/jrtc.c
new file mode 100644 (file)
index 0000000..f395cd9
--- /dev/null
@@ -0,0 +1,466 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include "obj.h"
+#include "runtime.h"
+
+#if MICROPY_QPY_MODULE_JRTC
+#include "callbackdeal.h"
+#include "jrtc.h"
+#include "jrtc0.h"
+#include "helios.h"
+#include "helios_debug.h"
+#include "helios_datacall.h"
+#ifdef CONFIG_LVGL
+#include "lvgl.h"
+#endif
+#include <helios_lcd.h>
+#include <helios_pwm.h>
+#include <helios_gpio.h>
+
+#define HELIOS_JRTC_LOG(msg, ...)      custom_log("JRTC", msg, ##__VA_ARGS__)
+
+static Helios_LCDInitStruct init_data = {0};
+#define XSTART_H 0xf0
+#define XSTART_L 0xf1
+#define YSTART_H 0xf2
+#define YSTART_L 0xf3
+#define XEND_H 0xE0
+#define XEND_L 0xE1
+#define YEND_H 0xE2
+#define YEND_L 0xE3
+#define XSTART 0xD0
+#define XEND 0xD1
+#define YSTART 0xD2
+#define YEND 0xD3
+#define PWM_FREQ        10000
+#define PWM_DUTY        0.2
+
+
+#define JRTC_ROTATE_0    (0)
+#define JRTC_ROTATE_90   (90)
+#define JRTC_ROTATE_180  (180)
+#define JRTC_ROTATE_270  (270)
+
+/** 通话错误值 */
+
+struct jrtc_t
+{
+    void* task; //必须放在头部
+    struct jrtc_t *next;
+    volatile unsigned char state, error;
+    char room[65], uid[65], vid[65], screen[65];
+    unsigned short srvIdx, gop, istats;//统计周期,默认5s
+    unsigned short video_cs_threshold;//卡顿阀值,默认300毫秒
+    unsigned short auto_req_slen;
+    struct AES_ctx *aes_ctx;
+    struct net_sock *tcpfd, *udpfd;
+    struct net_addr *udp_addr, *srv_addr;
+    unsigned char *recv_buf, *ared_buf, *vfec_buf;
+    unsigned short recv_off, ared_off;
+    unsigned hash, vfec_size, role, status;
+    struct jrtc_image_t *camera, *video;
+    unsigned audio_ssrc, video_ssrc;//local ssrc
+    unsigned char udp_fail_count;
+    char audio_pt, ared_pt;
+    char video_pt, vfec_pt;
+    unsigned short audio_seqno, video_seqno, vfec_seqno;
+    unsigned char audio_ptime;
+    unsigned char req_cam:2;
+    unsigned char req_batch:2;
+    unsigned char req_event:3;//1:status,2:role,3:video,4:index
+    unsigned char audio_received:1;
+    unsigned char video_started:1, audio_started:1, leave_called:1, video_changed:1;
+    unsigned char aenc_idx:2, adec_idx:2, venc_idx:2, vdec_idx:2;
+    char netst_pt, volu_pt;
+    signed char index;
+    unsigned char video_index;
+    unsigned char recv_types;//RECV_TYPE
+    unsigned recv_ms, send_ms, stats_ms, last_ms;
+    struct rtp_lostr_t* audio_lostR, *video_lostR;
+    struct rtp_stats_t* audio_stats, *video_stats;
+    unsigned recv_frame_count, recv_frame_ms;//fps
+    unsigned video_cs;//统计周期内(istats)卡顿毫秒数和
+    void (*effect_cb)(struct jrtc_photo_t* frame);
+    //发送请求处理
+    void* req_sem;
+    char req_id[65];
+    unsigned req_mask, req_value;
+};
+
+// enum jrtc_error err;
+int protect = 0;
+
+static struct jrtc_image_t send = {0};
+static struct jrtc_image_t recieve = {0};
+
+/* 定义jrtc_obj_t结构体 */
+typedef struct _jrtc_obj_t
+{
+    mp_obj_base_t base;   //定义的对象结构体要包含该成员
+}jrtc_obj_t;
+
+// 定义MsgQ数据类型
+typedef struct _jrtc_open_msg_t
+{
+    struct jrtc_image_t *video;
+    struct jrtc_image_t *camera;
+    char *ticket;
+    char *roomid;
+}jrtc_open_msg_t;
+
+const mp_obj_type_t jrtc_type;
+
+/** 当前的版本号 */
+#define JRTC_VERTION   "1.4.0"
+
+
+static Helios_MsgQ_t int_happen_q = 0;
+static Helios_Thread_t int_handle_task_id = 0;
+
+//mp_buffer_info_t roomid, ticket;
+static struct jrtc_t* test = NULL;
+static c_callback_t *usr_callback = NULL;
+static c_callback_t cb = {0};
+
+char *ticket_temp = NULL;
+char *roomid_temp = NULL;
+
+#ifdef CONFIG_LVGL
+lv_obj_t *jrtc_img = NULL;
+lv_img_dsc_t img_dsc;
+int update_display(uint8_t *camera_buffer, int width, int height) {
+    img_dsc.header.always_zero = 0;
+    img_dsc.header.w = width;
+    img_dsc.header.h = height;
+    img_dsc.data_size = width * height * 2; // RGB565格式是2字节/像素
+    img_dsc.header.cf = LV_IMG_CF_TRUE_COLOR;
+    img_dsc.data = (uint8_t *)camera_buffer;
+
+    // 更新LVGL图像
+    if (jrtc_img) {
+        lv_img_set_src(jrtc_img, &img_dsc);
+        return 1;
+    }
+    return 0;
+}
+
+typedef struct mp_lv_obj_t {
+    mp_obj_base_t base;
+    lv_obj_t *lv_obj;
+    lv_obj_t *callbacks;
+} mp_lv_obj_t;
+extern mp_int_t mp_lv_obj_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
+STATIC mp_obj_t get_native_obj(mp_obj_t *mp_obj)
+{
+    if (!MP_OBJ_IS_OBJ(mp_obj)) return mp_obj;
+    const mp_obj_type_t *native_type = ((mp_obj_base_t*)mp_obj)->type;
+    if (native_type == NULL)
+        return NULL;
+    if (native_type->parent == NULL || 
+        (native_type->buffer_p.get_buffer == mp_lv_obj_get_buffer))
+       return mp_obj;
+    while (native_type->parent) native_type = native_type->parent;
+    return mp_obj_cast_to_native_base(mp_obj, MP_OBJ_FROM_PTR(native_type));
+}
+
+STATIC inline lv_obj_t *mp_to_lv(mp_obj_t *mp_obj)
+{
+    if (mp_obj == NULL || mp_obj == mp_const_none) return NULL;
+    mp_obj_t native_obj = get_native_obj(mp_obj);
+    if (mp_obj_get_type(native_obj)->buffer_p.get_buffer != mp_lv_obj_get_buffer)
+        return NULL;
+    mp_lv_obj_t *mp_lv_obj = MP_OBJ_TO_PTR(native_obj);
+    return mp_lv_obj->lv_obj;
+}
+
+
+STATIC mp_obj_t set_img(mp_obj_t *mp_obj) {
+    lv_obj_t *obj = mp_to_lv(mp_obj);
+
+    if (obj) {
+        jrtc_img = obj;
+        return mp_obj_new_int(1);
+    } else {
+        return mp_obj_new_int(0);
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_img_obj, set_img);
+
+STATIC mp_obj_t remove_img(void) {
+    jrtc_img = NULL;
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(remove_img_obj, remove_img);
+#endif
+
+void jrtc_handle(void * argv) {
+    jrtc_open_msg_t open_msg = {0};
+    int ret = -1;
+    while (1) {
+        ret = Helios_MsgQ_Get(int_happen_q, (void *)&open_msg, sizeof(jrtc_open_msg_t), HELIOS_WAIT_FOREVER);
+               if (ret != 0)
+               {
+                       HELIOS_JRTC_LOG("interrupt handle thread failed to get queue\n");
+                       continue;
+               }
+        HELIOS_JRTC_LOG("roomid:%s, ticket:%s, video:%x, camera:%x.", open_msg.roomid, open_msg.ticket, open_msg.video, open_msg.camera);
+
+        if (test == NULL) {
+            test = jrtc_open(open_msg.roomid, open_msg.ticket, open_msg.video, open_msg.camera);
+            if (test == NULL) {
+                HELIOS_JRTC_LOG("jrtc_open fail\n");
+                continue;
+            }
+            jrtc_activate(test, JRTC_AUDIO|JRTC_CAMERA);
+            // 等待对方视频对讲结束
+            while(jrtc_state(test) != JRTC_CLOSED)
+            {
+            #ifdef CONFIG_JRTC_WITH_CAMERA
+                struct jrtc_image_t* image;
+                image = &recieve;
+                if (image->get != image->put) {
+                    update_display(image->data, image->width, image->height);
+                    image->get = image->put;
+                }
+            #endif
+                Helios_msleep(20);
+            }
+
+            // 判断是对方挂断,产生回调
+            st_CallBack_jrtc *jrtc_int = malloc(sizeof(st_CallBack_jrtc));
+            if(NULL != jrtc_int) { 
+                jrtc_int->result = 0;
+                jrtc_int->callback = cb;
+                qpy_send_msg_to_callback_deal_thread(CALLBACK_TYPE_ID_JRTC, jrtc_int);
+            }
+        }
+        else {
+            HELIOS_JRTC_LOG("jrtc has opened\n");
+        }
+    }
+}
+
+
+// 注册回调函数
+STATIC mp_obj_t set_callback(const mp_obj_t handler)
+{
+    usr_callback = &cb;
+    mp_sched_schedule_callback_register(usr_callback, handler);
+
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_set_callback_obj, set_callback);
+
+STATIC mp_obj_t mp_jrtc_init(void) {
+    Helios_ThreadAttr attr = {0};
+       if (int_happen_q == 0) {
+               int_happen_q = Helios_MsgQ_Create(1, sizeof(jrtc_open_msg_t));
+       }
+       if(int_handle_task_id == 0)
+       {
+           attr.name = "jrtc_handle";
+        attr.stack_size = 1024*4;
+        attr.priority = 90;
+        attr.entry = jrtc_handle;
+
+        int_handle_task_id = Helios_Thread_Create(&attr);
+        if (0 == int_handle_task_id)
+        {
+            mp_raise_ValueError("create interrupt handle task failed\n");
+        }
+       }
+
+
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_jrtc_init_obj, mp_jrtc_init);
+
+STATIC mp_obj_t mp_jrtc_config_server (mp_obj_t config_server)
+{
+    char *config_s= (char*)mp_obj_str_get_str(config_server);
+    jrtc_config_server(config_s);
+
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_jrtc_config_server_obj, mp_jrtc_config_server);
+
+
+STATIC mp_obj_t mp_jrtc_config (size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+    int ret = 0;
+    static Helios_DataCallInfoStruct datacall_info = {0};
+    Helios_DataCall_GetInfo(1, 0, &datacall_info);
+    enum { ARG_appkey, ARG_uid, ARG_srvURL,  ARG_key};
+    static const mp_arg_t allowed_args[] = 
+    {
+       { MP_QSTR_appkey,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_uid,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_srvURL,      MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_key,      MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+    };
+    mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args , args , kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
+
+    char *appkey_temp = (char *)mp_obj_str_get_str(vals[ARG_appkey].u_obj);
+    char *uid_temp = (char *)mp_obj_str_get_str(vals[ARG_uid].u_obj);
+    char *srvURL_temp = (char *)mp_obj_str_get_str(vals[ARG_srvURL].u_obj);
+    char *key_temp = (char *)mp_obj_str_get_str(vals[ARG_key].u_obj);
+
+    jrtc_config(appkey_temp, uid_temp, srvURL_temp, key_temp);
+    _jrtc_net_info = &datacall_info;
+    protect = 1;
+    ret = 1;
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mp_jrtc_config_obj, 4 ,mp_jrtc_config);
+
+
+STATIC mp_obj_t mp_jrtc_open (size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+    int ret = 0;
+    jrtc_open_msg_t open_msg = {0};
+
+    HELIOS_JRTC_LOG("mp_jrtc_open execute!!!");
+    if(protect != 1){
+        HELIOS_JRTC_LOG("Not config\n");
+        ret = -1;
+        return mp_obj_new_int(-1);
+    }
+    enum { ARG_roomid, ARG_ticket, ARG_recieve, ARG_send};
+    static const mp_arg_t allowed_args[] = 
+    {
+       { MP_QSTR_roomid,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_ticket,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_recieve,      MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_send,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+    };
+    mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args , args , kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
+
+    roomid_temp = (char *)mp_obj_str_get_str(vals[ARG_roomid].u_obj);
+    ticket_temp = (char *)mp_obj_str_get_str(vals[ARG_ticket].u_obj);
+    
+    size_t len;
+    mp_obj_t *elem;
+    mp_obj_get_array(vals[ARG_recieve].u_obj, &len, &elem);
+    HELIOS_JRTC_LOG("mp_jrtc_open recieve para len:%d", len);
+    if (len == 4) {
+        recieve.fps = mp_obj_get_int(elem[0]);
+        recieve.kbps = mp_obj_get_int(elem[1]);
+        recieve.width = mp_obj_get_int(elem[2]);
+        recieve.height= mp_obj_get_int(elem[3]);
+        open_msg.video = &recieve;
+    } else if (len == 0){
+        open_msg.video = NULL;
+    } else {
+        mp_raise_ValueError("video parameter num error\n");
+    }
+    
+    mp_obj_get_array(vals[ARG_send].u_obj, &len, &elem);
+    HELIOS_JRTC_LOG("mp_jrtc_open send para len:%d", len);
+    if (len == 4) {
+        send.fps = mp_obj_get_int(elem[0]);
+        send.kbps = mp_obj_get_int(elem[1]);
+        send.width = mp_obj_get_int(elem[2]);
+        send.height = mp_obj_get_int(elem[3]);
+        open_msg.camera = &send;
+    } else if (len == 0){
+        open_msg.camera = NULL;
+    } else {
+        mp_raise_ValueError("video parameter num error\n");
+    }
+    open_msg.ticket = ticket_temp;
+    open_msg.roomid = roomid_temp;
+
+    Helios_MsgQ_Put(int_happen_q, (const void *)&open_msg, sizeof(jrtc_open_msg_t), HELIOS_NO_WAIT);
+    
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mp_jrtc_open_obj, 4, mp_jrtc_open);
+
+
+STATIC mp_obj_t mp_jrtc_close (mp_obj_t err_j)
+{
+    int ret = 0;
+    int err = mp_obj_get_int(err_j);
+    if((err != 0) && (err != 1) && (err != 64) && (err != 71) && (err != 90) && (err != 104) && 
+    (err != 101) && (err != 111) && (err != 128) && (err != 129) && (err != 130) && (err != 131) && 
+    (err != 132) && (err != 133) && (err != 134) && (err != 135) && (err != 136) && (err != 137) &&
+    (err != 138) && (err != 252) && (err != 253) && (err != 254) &&(err != 255))
+    {
+        HELIOS_JRTC_LOG("err_j is invalid\n");
+        ret = -1;
+        return mp_obj_new_int(ret);
+    }
+    else {
+        if (test == NULL) {
+            return mp_obj_new_int(1);
+        }
+        MP_THREAD_GIL_EXIT();
+        jrtc_close(test, err);
+        MP_THREAD_GIL_ENTER();
+        test = NULL;
+        ret = 1;
+        return mp_obj_new_int(ret);
+    }
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_jrtc_close_obj, mp_jrtc_close);
+
+STATIC mp_obj_t mp_jrtc_get_state(void)
+{
+    int sta = jrtc_state(test);
+
+    return mp_obj_new_int(sta);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_jrtc_get_state_obj, mp_jrtc_get_state);
+
+#ifdef CONFIG_JRTC_WITH_CAMERA
+STATIC mp_obj_t mp_jrtc_set_cam_angle(mp_obj_t angle_j) {
+    int cam_angle = mp_obj_get_int(angle_j);
+       if ((cam_angle<JRTC_ROTATE_0) || (cam_angle>JRTC_ROTATE_270)) {
+               mp_raise_ValueError("Camera rotation Angle is out of range!!!");
+       }
+    _jrtc_cam_angle = cam_angle;
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_jrtc_set_cam_angle_obj, mp_jrtc_set_cam_angle);
+#endif
+
+/* 定义的modjrtc本地字典 */
+STATIC const mp_rom_map_elem_t jrtc_globals_table[] = {
+    {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_jrtc)},   //这个对应python层面的__name__ 属性
+    {MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&mp_jrtc_config_obj)}, //新增的modtest_obj_func_withargs对象注册到modtest中
+    {MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_jrtc_open_obj)}, 
+    {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_jrtc_close_obj)},
+    {MP_ROM_QSTR(MP_QSTR_set_callback), MP_ROM_PTR(&mp_set_callback_obj)},
+    {MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mp_jrtc_init_obj)},
+    {MP_ROM_QSTR(MP_QSTR_config_server), MP_ROM_PTR(&mp_jrtc_config_server_obj)},
+#ifdef CONFIG_LVGL
+    {MP_ROM_QSTR(MP_QSTR_set_img), MP_ROM_PTR(&set_img_obj)},
+    {MP_ROM_QSTR(MP_QSTR_remove_img), MP_ROM_PTR(&remove_img_obj)},
+#endif
+    {MP_ROM_QSTR(MP_QSTR_get_state), MP_ROM_PTR(&mp_jrtc_get_state_obj)},
+#ifdef CONFIG_JRTC_WITH_CAMERA   
+    {MP_ROM_QSTR(MP_QSTR_set_cam_angle), MP_ROM_PTR(&mp_jrtc_set_cam_angle_obj)},
+#endif
+    { MP_ROM_QSTR(MP_QSTR_CAM_ROTATE_0),        MP_ROM_INT(JRTC_ROTATE_0) },
+       { MP_ROM_QSTR(MP_QSTR_CAM_ROTATE_90),        MP_ROM_INT(JRTC_ROTATE_90) },
+       { MP_ROM_QSTR(MP_QSTR_CAM_ROTATE_180),        MP_ROM_INT(JRTC_ROTATE_180) },
+       { MP_ROM_QSTR(MP_QSTR_CAM_ROTATE_270),        MP_ROM_INT(JRTC_ROTATE_270) },
+};
+
+/* 把modjrtc_globals_table注册到 mp_module_modjrtc_globals里面去 */
+//STATIC MP_DEFINE_CONST_DICT(jrtc_locals_dict, jrtc_locals_dict_table);  
+STATIC MP_DEFINE_CONST_DICT(mp_module_jrtc_globals, jrtc_globals_table); 
+
+/* 定义mp_obj_type_t类型的结构体;注意这里和定义module使用的类型是不一样的 */
+const mp_obj_module_t mp_module_jrtc = {
+    .base={ &mp_type_module }, 
+    //.name = MP_QSTR_jrtc, //type类的name属性是放在这里定义,而不是放在DICT中
+    //.make_new = can_mcp2515_make_new, //添加的make new属性
+    .globals = (mp_obj_dict_t*)&mp_module_jrtc_globals, //注册jrtc_locals_dict
+};
+
+#endif
\ No newline at end of file
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modG722.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modG722.c
new file mode 100644 (file)
index 0000000..59e7951
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ ******************************************************************************
+ * @file    modG722.c
+ * @author  Elian
+ * @version V1.0.0
+ * @date    2024/06/11
+ * @brief   G722
+ ******************************************************************************
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "obj.h"
+#include <string.h>
+#include "runtime.h"
+#include "mphalport.h"
+
+#if MICROPY_QPY_MODULE_G722
+
+#include "helios_debug.h"
+#include "helios_audio.h"
+
+#include "g722.h"
+
+#define MOD_G722_LOG(msg, ...) custom_log(G722, msg, ##__VA_ARGS__)
+
+typedef struct _machine_pcm_obj_t
+{
+       mp_obj_base_t base;
+       void *handle_read;
+       void *handle_write;
+       int mic_channel;
+       unsigned int channels;
+       unsigned int samplerate;
+       unsigned int flags;
+} machine_pcm_obj_t;
+
+typedef struct _G722_obj_t
+{
+       mp_obj_base_t base;
+       machine_pcm_obj_t pcm_handler;
+} G722_obj_t;
+
+const mp_obj_type_t mp_G722_type;
+
+enum
+{
+       PCM_FLAG_READ_ONLY,
+       PCM_FLAG_WRITE_ONLY,
+       PCM_FLAG_WRITE_READ,
+       PCM_FLAG_MAX,
+};
+
+static bool is_support_samplerate(unsigned int rate)
+{
+       switch (rate)
+       {
+       case 8000:
+       case 16000:
+               return true;
+       }
+       return false;
+}
+
+static g722_encode_state_t *encoder_sta = NULL;
+static g722_decode_state_t *decoder_sta = NULL;
+
+STATIC mp_obj_t G722_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
+{
+       G722_obj_t *self = m_new_obj_with_finaliser(G722_obj_t);
+       int bitrate = 64000;
+    int flags = 0;
+
+       self->base.type = &mp_G722_type;
+
+       if (n_args != 2)
+       {
+               mp_raise_ValueError("Only pcm handle must be passed in");
+       }
+
+       machine_pcm_obj_t *pcm_handler = MP_OBJ_TO_PTR(args[0]);
+
+       if ((pcm_handler->channels != 1 && pcm_handler->channels) || (true != is_support_samplerate(pcm_handler->samplerate)) || (pcm_handler->flags >= PCM_FLAG_MAX))
+       {
+               mp_raise_ValueError("The input pcm handle is abnormal");
+       }
+       
+       bitrate = mp_obj_get_int(args[1]);
+       if (bitrate != 64000 && bitrate != 56000 && bitrate != 48000) {
+               mp_raise_ValueError("The input bitrate is abnormal");
+       }
+
+       MOD_G722_LOG("handle_r[%x], handle_w[%x], mic_channel[%d], channels[%d], samplerate[%d], flags[%d], bitrate[%d]\r\n",
+                                pcm_handler->handle_read, pcm_handler->handle_write, pcm_handler->mic_channel, pcm_handler->channels,
+                                pcm_handler->samplerate, pcm_handler->flags, bitrate);
+
+       memcpy(&(self->pcm_handler), pcm_handler, sizeof(machine_pcm_obj_t));
+
+       decoder_sta = g722_decode_init(NULL, bitrate, flags);
+       encoder_sta = g722_encode_init(NULL, bitrate, flags);
+       
+
+       return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t G722_write(mp_obj_t self_in, mp_obj_t buf_in)
+{
+       int ret;
+       G722_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+       if (self->pcm_handler.flags == PCM_FLAG_READ_ONLY || self->pcm_handler.handle_write == NULL)
+       {
+               mp_raise_ValueError("This pcm only supports read operations");
+       }
+
+       mp_buffer_info_t bufinfo;
+       mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+
+       if (0 == bufinfo.len || NULL == bufinfo.buf)
+       {
+               mp_raise_ValueError("Abnormal input buffer");
+       }
+
+       uint8_t *inbuf = bufinfo.buf;
+       int16_t *outbuf = NULL;
+       outbuf = (int16_t *)malloc(bufinfo.len * 4);
+       
+       if (outbuf == NULL) {
+               mp_raise_ValueError("malloc outbuf failed !!!");
+       }
+
+       int outlen = g722_decode(decoder_sta, outbuf, (const uint8_t*)inbuf, bufinfo.len);
+       //MOD_G722_LOG("inbuf len:[%d], outbuf len:[%d]\r\n", bufinfo.len, outlen);
+       int bytes_written = Helios_PCM_Write(self->pcm_handler.handle_write, (void *)outbuf, outlen*sizeof(int16_t));
+       if (outbuf != NULL) {
+               free(outbuf);
+       }
+
+       return mp_obj_new_int(bytes_written);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(G722_write_obj, G722_write);
+
+
+STATIC mp_obj_t G722_read(mp_obj_t self_in)
+{
+       G722_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+       int frame_len = self->pcm_handler.samplerate * 20 / 1000 * 2;
+
+       int16_t inbuf[320] = {0};
+       uint8_t outbuf[640] = {0};
+
+       if (self->pcm_handler.flags == PCM_FLAG_WRITE_ONLY || self->pcm_handler.handle_read == NULL)
+       {
+               mp_raise_ValueError("This pcm only supports write operations");
+       }
+
+       int bytes_read = Helios_PCM_Read(self->pcm_handler.handle_read, inbuf, frame_len);
+       if (bytes_read < 0)
+       {
+               mp_raise_ValueError("PCM failed to read data");
+       }
+       int outlen = g722_encode(encoder_sta, outbuf, (const int16_t*)inbuf, frame_len/sizeof(int16_t));
+       return mp_obj_new_bytes(outbuf, outlen);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(G722_read_obj, G722_read);
+
+STATIC const mp_rom_map_elem_t G722_locals_dict_table[] = {
+       {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_G722)},
+       {MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&G722_write_obj)},
+       {MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&G722_read_obj)},
+};
+STATIC MP_DEFINE_CONST_DICT(G722_locals_dict, G722_locals_dict_table);
+
+const mp_obj_type_t mp_G722_type = {
+       {&mp_type_type},
+       .name = MP_QSTR_G722,
+       .make_new = G722_make_new,
+       .locals_dict = (mp_obj_dict_t *)&G722_locals_dict,
+};
+
+#endif /* MICROPY_QPY_MODULE_G722 */
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modalipay_collection.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modalipay_collection.c
new file mode 100644 (file)
index 0000000..d0caed8
--- /dev/null
@@ -0,0 +1,505 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "obj.h"
+#include "runtime.h"
+#include "mperrno.h"
+
+#if MICROPY_QPY_MODULE_ALIPAY_COLLECTION
+
+#include "helios_os.h"
+#include "helios_debug.h"
+#include "helios_alipay_collection.h"
+#include "callbackdeal.h"
+
+#define QPY_ALIPAY_COLLECTION_LOG(msg, ...)      custom_log("ALIPAY_COLLECTION", msg, ##__VA_ARGS__)
+
+
+/* 定义AliPay_obj_t结构体 */
+typedef struct _ALIPAY_COLLECTION_obj_t
+{
+    mp_obj_base_t base;   //定义的对象结构体要包含该成员
+}ALIPAY_COLLECTION_obj_t;
+
+const mp_obj_type_t ALIPAY_COLLECTION_type;
+ALIPAY_COLLECTION_obj_t *single_alipay_collection = NULL;
+
+
+/*
+* QPY接口
+*/
+STATIC mp_obj_t ALIPAY_COLLECTION_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
+{
+    mp_arg_check_num(n_args, n_kw, 0, 7, false);   //检查参数个数
+    if( single_alipay_collection == NULL ) {
+               single_alipay_collection = m_new_obj_with_finaliser(ALIPAY_COLLECTION_obj_t);  //创建对象,分配空间
+       }
+       ALIPAY_COLLECTION_obj_t *self = single_alipay_collection;
+       self->base.type = &ALIPAY_COLLECTION_type;         //定义对象的类型
+
+    int ret = 0;
+    Helios_aliapy_iot_save Helios_aliapy_save = {0};
+
+    switch(n_args){
+        case 7:{
+            mp_buffer_info_t product_key_info;
+            mp_get_buffer_raise(args[6], &product_key_info, MP_BUFFER_READ);
+            if(product_key_info.len == 0 || product_key_info.len > (64 + 1)) {
+                QPY_ALIPAY_COLLECTION_LOG("invalid product_key\n\r");
+                ret = -1;
+                break;
+            }
+            memcpy(Helios_aliapy_save.profile_info_st.product_key, product_key_info.buf, product_key_info.len);
+            QPY_ALIPAY_COLLECTION_LOG("profile info, product_key = %s\n\r", Helios_aliapy_save.profile_info_st.product_key);
+            //no break
+        }
+        
+        case 6:{
+            mp_buffer_info_t merchant_user_id_info;
+            mp_get_buffer_raise(args[5], &merchant_user_id_info, MP_BUFFER_READ);
+            if(merchant_user_id_info.len == 0 || merchant_user_id_info.len > (32 + 1)) {
+                QPY_ALIPAY_COLLECTION_LOG("invalid merchant_user_id\n\r");
+                ret = -1;
+                break;
+            }
+            memcpy(Helios_aliapy_save.profile_info_st.merchant_user_id, merchant_user_id_info.buf, merchant_user_id_info.len);
+            QPY_ALIPAY_COLLECTION_LOG("profile info, merchant_user_id = %s\n\r", Helios_aliapy_save.profile_info_st.merchant_user_id);
+            //no break
+        }
+        
+        case 5:{
+            mp_buffer_info_t dev_id_info;
+            mp_get_buffer_raise(args[4], &dev_id_info, MP_BUFFER_READ);
+            if(dev_id_info.len == 0 || dev_id_info.len > (32 + 1)) {
+                QPY_ALIPAY_COLLECTION_LOG("invalid dev_id\n\r");
+                ret = -1;
+                break;
+            }
+            memcpy(Helios_aliapy_save.profile_info_st.device_supplier_no, dev_id_info.buf, dev_id_info.len);
+            QPY_ALIPAY_COLLECTION_LOG("profile info, dev_id = %s\n\r", Helios_aliapy_save.profile_info_st.device_supplier_no);
+            //no break
+        }
+        
+        case 4:{
+            mp_buffer_info_t module_id_info;
+            mp_get_buffer_raise(args[3], &module_id_info, MP_BUFFER_READ);
+            if(module_id_info.len == 0 || module_id_info.len > (64 + 1)) {
+                QPY_ALIPAY_COLLECTION_LOG("invalid module_id\n\r");
+                ret = -1;
+                break;
+            }
+            memcpy(Helios_aliapy_save.profile_info_st.module_supplier_no, module_id_info.buf, module_id_info.len);
+            QPY_ALIPAY_COLLECTION_LOG("profile info, module_id = %s\n\r", Helios_aliapy_save.profile_info_st.module_supplier_no);
+            //no break
+        }
+        
+        case 3:{
+            mp_buffer_info_t item_id_info;
+            mp_get_buffer_raise(args[2], &item_id_info, MP_BUFFER_READ);
+            if(item_id_info.len == 0 || item_id_info.len > (64 + 1)) {
+                QPY_ALIPAY_COLLECTION_LOG("invalid item_id\n\r");
+                ret = -1;
+                break;
+            }
+            memcpy(Helios_aliapy_save.profile_info_st.item_id, item_id_info.buf, item_id_info.len);
+            QPY_ALIPAY_COLLECTION_LOG("profile info, item_id = %s\n\r", Helios_aliapy_save.profile_info_st.item_id);
+            //no break;
+        }
+        
+        case 2:{
+            mp_buffer_info_t sn_info;
+            mp_get_buffer_raise(args[1], &sn_info, MP_BUFFER_READ);
+            if(sn_info.len == 0 || sn_info.len > (64 + 1)) {
+                QPY_ALIPAY_COLLECTION_LOG("invalid sn\n\r");
+                ret = -1;
+                break;
+            }
+            memcpy(Helios_aliapy_save.terminal_id, sn_info.buf, sn_info.len);
+            QPY_ALIPAY_COLLECTION_LOG("profile info, sn = %s\n\r", Helios_aliapy_save.terminal_id);
+
+            //no break
+        }
+        
+        case 1:{
+            Helios_aliapy_save.profile_info_st.env = mp_obj_get_int(args[0]);
+            QPY_ALIPAY_COLLECTION_LOG("profile env = %d\n\r", Helios_aliapy_save.profile_info_st.env);
+            break;
+        }
+        
+        default:
+            QPY_ALIPAY_COLLECTION_LOG("profile info error");
+            ret = -1;
+            break;
+    }
+    
+    if(ret == -1){
+        return mp_obj_new_int(ret);
+    }
+
+    ret = Helios_alipay_iot_set_save(&Helios_aliapy_save);
+    if(ret == -1)
+    {
+        return mp_obj_new_int(ret);
+    }
+    
+    return MP_OBJ_FROM_PTR(self);                 //返回对象的指针
+}
+
+STATIC c_callback_t *alipay_callback = NULL;
+
+static void helios_alipay_callback_to_python(int msgID, int data)
+{      
+       if(alipay_callback == NULL) {
+               return;
+       }
+#if MICROPY_ENABLE_CALLBACK_DEAL
+    st_CallBack_ALIPAY_COLLECTION *alipay_collection_msg = malloc(sizeof(st_CallBack_ALIPAY_COLLECTION));
+    if(NULL != alipay_collection_msg)
+    {
+        alipay_collection_msg->msgID = msgID;
+        alipay_collection_msg->data = data;
+        alipay_collection_msg->callback = *alipay_callback;
+        qpy_send_msg_to_callback_deal_thread(CALLBACK_TYPE_ID_ALIPAY_COLLECTION, alipay_collection_msg);
+    }
+#else
+    mp_sched_schedule_ex(alipay_callback, mp_const_none);
+#endif
+}
+
+STATIC mp_obj_t register_event_callback(mp_obj_t self_in, mp_obj_t callback)
+{
+    (void)self_in;
+
+    int ret = 0;
+    
+    if (callback != mp_const_none) {
+        static c_callback_t cb = {0};
+        memset(&cb, 0, sizeof(c_callback_t));
+       alipay_callback = &cb;
+       mp_sched_schedule_callback_register(alipay_callback, callback);
+    }
+    
+    MP_THREAD_GIL_EXIT();
+       ret  = Helios_alipay_set_callback(helios_alipay_callback_to_python);
+       MP_THREAD_GIL_ENTER();
+    
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t alipay_init(mp_obj_t self_in)
+{
+    (void)self_in;    
+    return mp_obj_new_int(Helios_alipay_iot_init());
+}
+
+STATIC mp_obj_t iot_ctx_info_dump(mp_obj_t self_in)
+{
+    (void)self_in;
+    Helios_aliapy_iot_ctx_ptr iot_ctx_ptr = Helios_alipay_iot_get_ctx();
+       if(iot_ctx_ptr == NULL){
+               return mp_obj_new_int(kGeneralErr);
+       }
+    
+    mp_obj_t key_tuple[15] = {
+        mp_obj_new_int(iot_ctx_ptr->state),
+        mp_obj_new_int(iot_ctx_ptr->running),
+        mp_obj_new_int(iot_ctx_ptr->iot_app_tid),
+        mp_obj_new_int(iot_ctx_ptr->iot_sdk_tid),
+        mp_obj_new_int(iot_ctx_ptr->clear_sdk_cache),
+        mp_obj_new_str(iot_ctx_ptr->account_iccid, strlen(iot_ctx_ptr->account_iccid)),
+        mp_obj_new_str(iot_ctx_ptr->imei, strlen(iot_ctx_ptr->imei)),
+        mp_obj_new_str(iot_ctx_ptr->sn, strlen(iot_ctx_ptr->sn)),
+        mp_obj_new_str(iot_ctx_ptr->aliapy_iot_save.terminal_id, strlen(iot_ctx_ptr->aliapy_iot_save.terminal_id)),
+        mp_obj_new_str(iot_ctx_ptr->aliapy_iot_save.profile_info_st.module_supplier_no, strlen(iot_ctx_ptr->aliapy_iot_save.profile_info_st.module_supplier_no)),
+        mp_obj_new_str(iot_ctx_ptr->aliapy_iot_save.profile_info_st.device_supplier_no, strlen(iot_ctx_ptr->aliapy_iot_save.profile_info_st.device_supplier_no)),
+        mp_obj_new_str(iot_ctx_ptr->aliapy_iot_save.profile_info_st.merchant_user_id, strlen(iot_ctx_ptr->aliapy_iot_save.profile_info_st.merchant_user_id)),
+        mp_obj_new_str(iot_ctx_ptr->aliapy_iot_save.profile_info_st.item_id, strlen(iot_ctx_ptr->aliapy_iot_save.profile_info_st.item_id)),
+        mp_obj_new_str(iot_ctx_ptr->aliapy_iot_save.profile_info_st.product_key, strlen(iot_ctx_ptr->aliapy_iot_save.profile_info_st.product_key)),
+        mp_obj_new_int(iot_ctx_ptr->aliapy_iot_save.profile_info_st.env),
+    };
+    
+    return mp_obj_new_tuple(15, key_tuple);
+}
+
+STATIC mp_obj_t get_version_info(mp_obj_t self_in)
+{
+    (void)self_in;
+    char ver_buf[64] = {0};
+    char time_buf[64] = {0};
+    Helios_alipay_iot_get_version_info(ver_buf, time_buf, 64);
+    mp_obj_t key_tuple[2] = {
+        mp_obj_new_str(ver_buf, strlen(ver_buf)),
+        mp_obj_new_str(time_buf, strlen(time_buf)),
+    };
+    
+    return mp_obj_new_tuple(2, key_tuple);
+}
+
+STATIC mp_obj_t get_utc(mp_obj_t self_in)
+{
+    (void)self_in;
+    unsigned int utc = 0;
+    Helios_alipay_iot_get_utc(&utc);
+    
+    return mp_obj_new_int(utc);
+}
+
+STATIC mp_obj_t get_biztid(mp_obj_t self_in)
+{
+    (void)self_in;
+    char buf[64] = {0};
+    Helios_alipay_get_biztid(buf, 64);
+
+    return mp_obj_new_str(buf, strlen(buf));
+}
+
+STATIC mp_obj_t get_iotdid(mp_obj_t self_in)
+{
+    (void)self_in;
+    char buf[64] = {0};
+    Helios_alipay_get_iotdid(buf, 64);
+
+    return mp_obj_new_str(buf, strlen(buf));
+}
+
+STATIC mp_obj_t sign_qrcode(mp_obj_t self_in, mp_obj_t qrcode, mp_obj_t amount)
+{
+    (void)self_in;
+    HELIOS_ALIPAY_IOT_SIGN_RET ret = ALIPAY_IOT_SIGN_RV_UNKNOWN;
+    char *amount_str = NULL;
+    char result[800] = {0};
+    int len_result = sizeof(result)-1;
+
+    char *qrcode_str = (char *)mp_obj_str_get_str(qrcode);
+    if(amount != mp_const_none)
+    {
+        amount_str = (char *)mp_obj_str_get_str(amount);
+    }
+    ret = Helios_alipay_iot_sign_qrcode(qrcode_str, amount_str, result, &len_result);
+
+    if(ret == ALIPAY_IOT_SIGN_RV_OK)
+    {
+        mp_obj_t result_tuple[2] = {
+               mp_obj_new_str(result, len_result),
+               mp_obj_new_int(len_result),
+        };
+
+        return mp_obj_new_tuple(2, result_tuple);
+    }else{
+        return mp_obj_new_int(ret);
+    }
+}
+
+STATIC mp_obj_t sign_face(mp_obj_t self_in, mp_obj_t facetoken, mp_obj_t amount)
+{
+    (void)self_in;
+    HELIOS_ALIPAY_IOT_SIGN_RET ret = ALIPAY_IOT_SIGN_RV_UNKNOWN;
+    char *amount_str = NULL;
+    char result[800] = {0};
+    int len_result = sizeof(result)-1;
+
+    char *facetoken_str = (char *)mp_obj_str_get_str(facetoken);
+    if(amount != mp_const_none)
+    {
+        amount_str = (char *)mp_obj_str_get_str(amount);
+    }
+    ret = Helios_alipay_iot_sign_face_token(facetoken_str, amount_str, result, &len_result);
+    
+    if(ret == ALIPAY_IOT_SIGN_RV_OK)
+    {
+        mp_obj_t result_tuple[2] = {
+               mp_obj_new_str(result, len_result),
+               mp_obj_new_int(len_result),
+        };
+
+        return mp_obj_new_tuple(2, result_tuple);
+    }else{
+        return mp_obj_new_int(ret);
+    }
+}
+
+STATIC mp_obj_t sign_recv_qrcode(mp_obj_t self_in, mp_obj_t tid, mp_obj_t amount)
+{
+    (void)self_in;
+    HELIOS_ALIPAY_IOT_SIGN_RET ret = ALIPAY_IOT_SIGN_RV_UNKNOWN;
+    char *amount_str = NULL;
+    char result[800] = {0};
+    int len_result = sizeof(result)-1;
+
+    char *tid_str = (char *)mp_obj_str_get_str(tid);
+    if(amount != mp_const_none)
+    {
+        amount_str = (char *)mp_obj_str_get_str(amount);
+    }
+    ret = Helios_alipay_iot_sign_recv_qrcode(tid_str, amount_str, result, &len_result);
+    
+    if(ret == ALIPAY_IOT_SIGN_RV_OK)
+    {
+        mp_obj_t result_tuple[2] = {
+               mp_obj_new_str(result, len_result),
+               mp_obj_new_int(len_result),
+        };
+
+        return mp_obj_new_tuple(2, result_tuple);
+    }else{
+        return mp_obj_new_int(ret);
+    }
+}
+
+STATIC mp_obj_t sign_delegated(mp_obj_t self_in, mp_obj_t tid, mp_obj_t amount)
+{
+    (void)self_in;
+    HELIOS_ALIPAY_IOT_SIGN_RET ret = ALIPAY_IOT_SIGN_RV_UNKNOWN;
+    char *amount_str = NULL;
+    char result[800] = {0};
+    int len_result = sizeof(result)-1;
+
+    char *tid_str = (char *)mp_obj_str_get_str(tid);
+    if(amount != mp_const_none)
+    {
+        amount_str = (char *)mp_obj_str_get_str(amount);
+    }
+    ret = Helios_alipay_iot_sign_delegated(tid_str, amount_str, result, &len_result);
+    
+    if(ret == ALIPAY_IOT_SIGN_RV_OK)
+    {
+        mp_obj_t result_tuple[2] = {
+               mp_obj_new_str(result, len_result),
+               mp_obj_new_int(len_result),
+        };
+
+        return mp_obj_new_tuple(2, result_tuple);
+    }else{
+        return mp_obj_new_int(ret);
+    }
+}
+
+STATIC mp_obj_t coll_action_report(mp_obj_t self_in)
+{
+    (void)self_in;
+    int ret = 0;
+    Helios_alipay_iot_action_data_struct action = {0};
+    
+    action.scan_count++;
+       action.brocast_count++;
+       ret = Helios_alipay_iot_coll_action_data_send(&action);
+       QPY_ALIPAY_COLLECTION_LOG("ret %d coll_action_report!\r\n", ret);
+    
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t coll_production_report(mp_obj_t self_in)
+{
+    (void)self_in;
+    int ret = 0;
+    char buf[64+1]={0};
+    Helios_alipay_iot_production_info_struct proinfo={0};
+    Helios_aliapy_iot_ctx_ptr iot_ctx_ptr = Helios_alipay_iot_get_ctx();
+    if( iot_ctx_ptr == NULL){
+        return mp_obj_new_int(kGeneralErr);
+    }
+    
+    if (!(iot_ctx_ptr->account_iccid[0])){
+               //tigger update again
+               ret = Helios_alipay_iot_get_type_info(HELIOS_ALIPAY_DEVICE_ICCID, buf, 64);
+               if(ret != 0)
+                       QPY_ALIPAY_COLLECTION_LOG("ret %d Helios_alipay_iot_get_type_info iccid err!\r\n", ret);
+       }
+       memcpy(proinfo.iccid, iot_ctx_ptr->account_iccid, sizeof(proinfo.iccid)-1);
+       memcpy(proinfo.account_flow , iot_ctx_ptr->account_iccid, sizeof(proinfo.account_flow)-1);
+       proinfo.human_verify = 0x01;
+       ret = Helios_alipay_iot_coll_production_info_send(&proinfo);
+       QPY_ALIPAY_COLLECTION_LOG("ret %d coll_production_report!\r\n", ret);
+    
+    return mp_obj_new_int(ret);
+}
+
+
+STATIC const mp_arg_t coll_transaction_report_args[] = 
+{
+       { MP_QSTR_amount,           MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } },
+    { MP_QSTR_time_stamp,       MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } },
+    { MP_QSTR_time_consuming,   MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } },
+    { MP_QSTR_qr_code,          MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } },
+    { MP_QSTR_business_no,      MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } },
+};
+STATIC mp_obj_t coll_transaction_report(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
+{
+    enum {ARG_amount, ARG_time_stamp, ARG_time_consuming, ARG_qr_code, ARG_business_no,};
+    
+    mp_arg_val_t args[MP_ARRAY_SIZE(coll_transaction_report_args)];
+    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,MP_ARRAY_SIZE(coll_transaction_report_args), coll_transaction_report_args, args);
+    
+    ALIPAY_COLLECTION_obj_t *self = (ALIPAY_COLLECTION_obj_t *)MP_OBJ_TO_PTR(pos_args[0]);
+    
+    int ret = 0;
+    Helios_alipay_iot_transaction_data_struct trans_data={0};
+    
+    trans_data.amount         = args[ARG_amount].u_int;
+       trans_data.timestamp      = args[ARG_time_stamp].u_int;
+       trans_data.time_consuming = args[ARG_time_consuming].u_int;
+    mp_buffer_info_t qr_code_info = {0}, business_no_info = {0};
+    if (args[ARG_qr_code].u_obj != mp_const_none) {
+        mp_get_buffer_raise(args[ARG_qr_code].u_obj, &qr_code_info, MP_BUFFER_READ);
+    }
+    if (args[ARG_business_no].u_obj != mp_const_none) {
+            mp_get_buffer_raise(args[ARG_business_no].u_obj, &business_no_info, MP_BUFFER_READ);
+    }
+       memcpy(trans_data.qr_code, qr_code_info.buf, qr_code_info.len);
+       memcpy(trans_data.business_no, business_no_info.buf, business_no_info.len);
+
+       ret = Helios_alipay_iot_coll_transaction_data_send(&trans_data);
+       QPY_ALIPAY_COLLECTION_LOG("ret %d coll_transaction_report!\r\n", ret);
+    
+    return mp_obj_new_int(ret);
+}
+
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(iot_ctx_info_dump_obj, iot_ctx_info_dump);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(alipay_init_obj, alipay_init);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(register_event_callback_obj, register_event_callback);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_version_info_obj, get_version_info);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_utc_obj, get_utc);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_biztid_obj, get_biztid);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_iotdid_obj, get_iotdid);
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(sign_qrcode_obj, sign_qrcode);
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(sign_face_obj, sign_face);
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(sign_recv_qrcode_obj, sign_recv_qrcode);
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(sign_delegated_obj, sign_delegated);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(coll_action_report_obj, coll_action_report);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(coll_production_report_obj, coll_production_report);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(coll_transaction_report_obj, 5, coll_transaction_report);
+
+/* 定义type的本地字典 */
+STATIC const mp_rom_map_elem_t ALIPAY_COLLECTION_locals_dict_table[] = {
+       { MP_OBJ_NEW_QSTR(MP_QSTR___name__),MP_ROM_QSTR(MP_QSTR_ALIPAY_COLLECTION) },
+       { MP_ROM_QSTR(MP_QSTR_get_iot_ctx_info), MP_ROM_PTR(&iot_ctx_info_dump_obj) },
+    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&alipay_init_obj) },
+    { MP_ROM_QSTR(MP_QSTR_event_callback), MP_ROM_PTR(&register_event_callback_obj) },
+    { MP_ROM_QSTR(MP_QSTR_get_version), MP_ROM_PTR(&get_version_info_obj) },
+    { MP_ROM_QSTR(MP_QSTR_get_utc), MP_ROM_PTR(&get_utc_obj) },
+    { MP_ROM_QSTR(MP_QSTR_get_biztid), MP_ROM_PTR(&get_biztid_obj) },
+    { MP_ROM_QSTR(MP_QSTR_get_iotdid), MP_ROM_PTR(&get_iotdid_obj) },
+    { MP_ROM_QSTR(MP_QSTR_sign_qrcode), MP_ROM_PTR(&sign_qrcode_obj) },
+    { MP_ROM_QSTR(MP_QSTR_sign_face), MP_ROM_PTR(&sign_face_obj) },
+    { MP_ROM_QSTR(MP_QSTR_sign_recv_qrcode), MP_ROM_PTR(&sign_recv_qrcode_obj) },
+    { MP_ROM_QSTR(MP_QSTR_sign_delegated), MP_ROM_PTR(&sign_delegated_obj) },
+    { MP_ROM_QSTR(MP_QSTR_report_coll_action), MP_ROM_PTR(&coll_action_report_obj) },
+    { MP_ROM_QSTR(MP_QSTR_report_coll_production), MP_ROM_PTR(&coll_production_report_obj) },
+    { MP_ROM_QSTR(MP_QSTR_report_coll_transaction), MP_ROM_PTR(&coll_transaction_report_obj) },
+};
+
+/* 把ALIPAY_COLLECTION_locals_dict_table注册到ALIPAY_COLLECTION_locals_dict里面去 */
+STATIC MP_DEFINE_CONST_DICT(ALIPAY_COLLECTION_locals_dict, ALIPAY_COLLECTION_locals_dict_table);
+
+/* 定义mp_obj_type_t类型的结构体;注意这里和定义module使用的类型是不一样的 */
+const mp_obj_type_t ALIPAY_COLLECTION_type = {
+    .base={ &mp_type_type }, 
+    .name = MP_QSTR_ALIPAY_COLLECTION, //type类的name属性是放在这里定义,而不是放在DICT中
+    .make_new = ALIPAY_COLLECTION_make_new, //添加的make new属性
+    .locals_dict = (mp_obj_dict_t*)&ALIPAY_COLLECTION_locals_dict, //注册ALIPAY_COLLECTION_locals_dict
+};
+    
+#endif
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modalipay_se.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modalipay_se.c
new file mode 100644 (file)
index 0000000..7406517
--- /dev/null
@@ -0,0 +1,574 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "obj.h"
+#include "runtime.h"
+#include "mperrno.h"
+
+#if MICROPY_QPY_MODULE_ALIPAY_SE
+
+#include "helios_os.h"
+#include "helios_debug.h"
+#include "helios_alipay_se.h"
+#include "helios_pin.h"
+
+#define QPY_ALIPAY_SE_LOG(msg, ...)      custom_log("ALIPAY_SE", msg, ##__VA_ARGS__)
+
+
+/* 定义AliPay_obj_t结构体 */
+typedef struct _ALIPAY_SE_obj_t
+{
+    mp_obj_base_t base;   //定义的对象结构体要包含该成员
+}ALIPAY_SE_obj_t;
+
+const mp_obj_type_t ALIPAY_SE_type;
+ALIPAY_SE_obj_t *single_alipay_se = NULL;
+
+
+/*
+* QPY接口
+*/
+STATIC mp_obj_t ALIPAY_SE_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
+{
+    mp_arg_check_num(n_args, n_kw, 0, 2, false);   //检查参数个数
+    if( single_alipay_se == NULL ) {
+               single_alipay_se = m_new_obj_with_finaliser(ALIPAY_SE_obj_t);  //创建对象,分配空间
+       }
+       ALIPAY_SE_obj_t *self = single_alipay_se;
+       self->base.type = &ALIPAY_SE_type;         //定义对象的类型
+
+    int se_i2c_no = -1, se_i2c_reset = -1;
+
+    switch(n_args)
+       {
+           case 2:
+               {
+                       se_i2c_reset = mp_obj_get_int(args[1]);
+                       if(se_i2c_reset != -1) {
+                if(!(se_i2c_reset > HELIOS_GPIO0 && se_i2c_reset < HELIOS_GPIOMAX)) {
+                    mp_raise_ValueError(MP_ERROR_TEXT("invalid IIC reset pin"));
+                    break;
+                }
+            }
+               }
+               case 1:
+               {       
+                       se_i2c_no = mp_obj_get_int(args[0]);
+                       if( se_i2c_no > 2 ) {
+                               mp_raise_TypeError(MP_ERROR_TEXT("invalid IIC Port"));
+                       }
+                       break;
+               }
+               default:
+                       mp_raise_OSError(MP_EFAULT);
+            break;
+    }
+
+    Helios_alipay_set_i2c_port(se_i2c_no, se_i2c_reset);
+
+    MP_THREAD_GIL_EXIT();
+    Helios_alipay_se_i2c_init();
+
+    int ret = Helios_alipay_pre_init();
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+    
+    return MP_OBJ_FROM_PTR(self);                 //返回对象的指针
+}
+
+STATIC mp_obj_t get_aid_code(mp_obj_t self_in) {
+    (void)self_in;
+
+    char aid_code[256] = {0};
+    uint32_t len_aid_code = sizeof(aid_code);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_get_aid_code(aid_code, &len_aid_code);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str(aid_code, len_aid_code);
+}
+
+STATIC mp_obj_t get_binding_code(mp_obj_t self_in) {
+    (void)self_in;
+
+    char result[256] = {0};
+    int len_result = sizeof(result);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_get_binding_code(result, &len_result);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str(result, len_result);
+}
+
+STATIC mp_obj_t query_binding_result(mp_obj_t self_in) {
+    (void)self_in;
+
+    binding_status_e result = 0;
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_query_binding_result(&result);
+    MP_THREAD_GIL_ENTER();
+
+    mp_obj_t result_tuple[2] = {
+        mp_obj_new_int(ret),
+        mp_obj_new_int(result),
+    };
+    
+    return mp_obj_new_tuple(2, result_tuple);
+}
+
+STATIC mp_obj_t get_paycode(mp_obj_t self_in) {
+    (void)self_in;
+
+    uint8_t result[20] = {0};
+    uint32_t len_result = sizeof(result);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_get_paycode(result, &len_result);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str((const char *)result, len_result);
+}
+
+STATIC mp_obj_t get_collectioncode(mp_obj_t self_in) {
+    (void)self_in;
+
+    uint8_t result[64] = {0};
+    uint32_t len_result = sizeof(result);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_get_collectioncode(result, &len_result);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str((const char *)result, len_result);
+}
+
+STATIC mp_obj_t query_order_result(mp_obj_t self_in, mp_obj_t pay_code) {
+    (void)self_in;
+
+    char bitmap_amount[32][14] = {0};
+    alipay_payment_status_e status = 0;
+    mp_buffer_info_t bufinfo;
+    
+    mp_get_buffer_raise(pay_code, &bufinfo, MP_BUFFER_READ);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_query_order_result((char *)bufinfo.buf, &status, bitmap_amount);
+    MP_THREAD_GIL_ENTER();
+    
+    if (ret != 0) {
+        return mp_obj_new_int(ret);
+    }
+
+    mp_obj_t result_tuple[2] = {
+        mp_obj_new_int(status),
+        mp_obj_new_bytearray(sizeof(bitmap_amount), (uint8_t *)bitmap_amount),
+    };
+    
+    return mp_obj_new_tuple(2, result_tuple);
+}
+
+STATIC mp_obj_t query_order_result_string(mp_obj_t self_in, mp_obj_t pay_code) {
+    (void)self_in;
+
+    char pay_amount[32] = {0};
+    char ext_data[256] = {0};
+    uint32_t ext_data_len = sizeof(ext_data);
+    alipay_payment_status_e status = 0;
+    mp_buffer_info_t bufinfo;
+    
+    mp_get_buffer_raise(pay_code, &bufinfo, MP_BUFFER_READ);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_query_order_result_string((char *)bufinfo.buf, &status, pay_amount, ext_data, &ext_data_len);
+    MP_THREAD_GIL_ENTER();
+    
+    if (ret != 0) {
+        return mp_obj_new_int(ret);
+    }
+
+    mp_obj_t result_tuple[3] = {
+        mp_obj_new_int(status),
+        mp_obj_new_str(pay_amount, strlen(pay_amount)),
+        mp_obj_new_str(ext_data, strlen(ext_data)),
+    };
+    
+    return mp_obj_new_tuple(3, result_tuple);
+}
+
+STATIC mp_obj_t query_income_details(mp_obj_t self_in, mp_obj_t collection_code) {
+    (void)self_in;
+
+    alipay_income_detail_info_t income_detail = {0};
+    mp_buffer_info_t bufinfo;
+    
+    mp_get_buffer_raise(collection_code, &bufinfo, MP_BUFFER_READ);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_query_income_details((char *)bufinfo.buf, &income_detail);
+    MP_THREAD_GIL_ENTER();
+    
+    if (ret != 0) {
+        return mp_obj_new_int(ret);
+    }
+
+    mp_obj_t result_tuple[3] = {
+        mp_obj_new_int(income_detail.is_success),
+        mp_obj_new_bytearray(sizeof(income_detail.bitmap_amount), (uint8_t *)income_detail.bitmap_amount),
+        mp_obj_new_str(income_detail.message, strlen(income_detail.message)),
+    };
+    
+    return mp_obj_new_tuple(3, result_tuple);
+}
+
+STATIC mp_obj_t query_flow_break(mp_obj_t self_in) {
+    (void)self_in;
+    
+    MP_THREAD_GIL_EXIT();
+    Helios_alipay_query_flow_break();
+    MP_THREAD_GIL_ENTER();
+    
+    return mp_const_none;
+}
+
+STATIC mp_obj_t check_active_status(mp_obj_t self_in) {
+    (void)self_in;
+
+    MP_THREAD_GIL_EXIT();
+    bool status = Helios_alipay_check_active_status();
+    MP_THREAD_GIL_ENTER();
+
+    return mp_obj_new_bool(status);
+}
+
+STATIC mp_obj_t get_active_request(mp_obj_t self_in) {
+    (void)self_in;
+
+    uint8_t buf_output[256] = {0};
+    uint32_t len_output = sizeof(buf_output);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_get_active_request(buf_output, &len_output);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str((const char *)buf_output, len_output);
+}
+
+STATIC mp_obj_t get_active_request_campt(mp_obj_t self_in, mp_obj_t model) {
+    (void)self_in;
+
+    uint8_t buf_output[256] = {0};
+    mp_buffer_info_t model_info;
+    uint32_t len_output = sizeof(buf_output);
+    
+    mp_get_buffer_raise(model, &model_info, MP_BUFFER_READ);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_get_active_request_campt((char *)model_info.buf, buf_output, &len_output);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str((const char *)buf_output, len_output);
+}
+
+STATIC mp_obj_t get_active_request_with_antchain(mp_obj_t self_in) {
+    (void)self_in;
+
+    uint8_t buf_output[256] = {0};
+    uint32_t len_output = sizeof(buf_output);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_get_active_request_with_antchain(buf_output, &len_output);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str((const char *)buf_output, len_output);
+}
+
+STATIC mp_obj_t save_active_response(mp_obj_t self_in, mp_obj_t input) {
+    (void)self_in;
+
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(input, &bufinfo, MP_BUFFER_READ);
+
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_save_active_response((uint8_t *)bufinfo.buf, (uint32_t)bufinfo.len);
+    MP_THREAD_GIL_ENTER();
+    
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t check_ecc_alg(mp_obj_t self_in) {
+    (void)self_in;
+
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_check_ecc_alg();
+    MP_THREAD_GIL_ENTER();
+    
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t secure_get_auth_data(mp_obj_t self_in) {
+    (void)self_in;
+
+    char auth_data[2048] = {0};
+    uint32_t len_auth_data = sizeof(auth_data);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_secure_get_auth_data(auth_data, &len_auth_data);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str(auth_data, len_auth_data);
+}
+
+STATIC mp_obj_t secure_rcv_dev_cert(mp_obj_t self_in, mp_obj_t input) {
+    (void)self_in;
+
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(input, &bufinfo, MP_BUFFER_READ);
+
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_secure_rcv_dev_cert((char *)bufinfo.buf);
+    MP_THREAD_GIL_ENTER();
+    
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t is_need_to_request_cert(mp_obj_t self_in) {
+    (void)self_in;
+
+    MP_THREAD_GIL_EXIT();
+    int ret = !(Helios_alipay_is_need_to_request_cert());
+    MP_THREAD_GIL_ENTER();
+    
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t get_binding_status(mp_obj_t self_in) {
+    (void)self_in;
+
+    MP_THREAD_GIL_EXIT();
+    bool status = Helios_alipay_get_binding_status();
+    MP_THREAD_GIL_ENTER();
+
+    return mp_obj_new_bool(status);
+}
+
+STATIC mp_obj_t get_logon_ID(mp_obj_t self_in) {
+    (void)self_in;
+
+    uint8_t id[128] = {0};
+    uint32_t len_id = sizeof(id);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_get_logon_ID(id, &len_id);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str((const char *)id, len_id);
+}
+
+STATIC mp_obj_t get_nick_name(mp_obj_t self_in) {
+    (void)self_in;
+
+    uint8_t nick_name[128] = {0};
+    uint32_t len_nick_name = sizeof(nick_name);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_get_nick_name(nick_name, &len_nick_name);
+    MP_THREAD_GIL_ENTER();
+    
+    if(ret != 0){
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_obj_new_str((const char *)nick_name, len_nick_name);
+}
+
+STATIC mp_obj_t unbinding(mp_obj_t self_in) {
+    (void)self_in;
+
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_unbinding();
+    MP_THREAD_GIL_ENTER();
+
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t reset_all(mp_obj_t self_in) {
+    (void)self_in;
+
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_alipay_reset_all();
+    MP_THREAD_GIL_ENTER();
+
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t enter_lpm(mp_obj_t self_in) {
+    (void)self_in;
+
+    MP_THREAD_GIL_EXIT();
+    Helios_alipay_se_enter_lpm();
+    MP_THREAD_GIL_ENTER();
+
+    return mp_const_none;
+}
+
+STATIC mp_obj_t exit_lpm(mp_obj_t self_in) {
+    (void)self_in;
+
+    MP_THREAD_GIL_EXIT();
+    Helios_alipay_se_exit_lpm();
+    MP_THREAD_GIL_ENTER();
+
+    return mp_const_none;
+}
+
+STATIC mp_obj_t set_vendor_info(mp_obj_t self_in, mp_obj_t name, mp_obj_t model) {
+    (void)self_in;
+
+    mp_buffer_info_t name_info = {0}, model_info = {0};
+    if (name != mp_const_none) {
+        mp_get_buffer_raise(name, &name_info, MP_BUFFER_READ);
+    }
+    if (model != mp_const_none) {
+        mp_get_buffer_raise(model, &model_info, MP_BUFFER_READ);
+    }
+       if (name_info.len > 20 || model_info.len > 20) {
+               return mp_obj_new_int(19);
+       }
+
+    Helios_alipay_set_vendor_info((char *)name_info.buf, (char *)model_info.buf);
+
+    return mp_obj_new_int(0);
+}
+
+STATIC mp_obj_t set_product_type(mp_obj_t self_in, mp_obj_t type) {
+    (void)self_in;
+
+       int product_type = mp_obj_get_int(type);
+    if (product_type != PRODUCT_TYPE_ADULT_WATCH && product_type != PRODUCT_TYPE_ADULT_BRACELET 
+               && product_type != PRODUCT_TYPE_ADULT_CARD && product_type != PRODUCT_TYPE_CHILD_WATCH 
+               && product_type != PRODUCT_TYPE_CHILD_BRACELET && product_type != PRODUCT_TYPE_STUDENT_CARD) {
+               return mp_obj_new_int(19);
+       }
+
+    Helios_alipay_set_product_type(product_type);
+
+    return mp_obj_new_int(0);
+}
+
+STATIC mp_obj_t alipay_se_delete(mp_obj_t self_in)
+{
+       (void)self_in;
+       return mp_obj_new_int(0);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_aid_code_obj, get_aid_code);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_binding_code_obj, get_binding_code);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(query_binding_result_obj, query_binding_result);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_paycode_obj, get_paycode);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_collectioncode_obj, get_collectioncode);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(query_order_result_obj, query_order_result);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(query_order_result_string_obj, query_order_result_string);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(query_income_details_obj, query_income_details);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(query_flow_break_obj, query_flow_break);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(check_active_status_obj, check_active_status);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_active_request_obj, get_active_request);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(get_active_request_campt_obj, get_active_request_campt);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_active_request_with_antchain_obj, get_active_request_with_antchain);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(save_active_response_obj, save_active_response);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(check_ecc_alg_obj, check_ecc_alg);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(secure_get_auth_data_obj, secure_get_auth_data);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(secure_rcv_dev_cert_obj, secure_rcv_dev_cert);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(is_need_to_request_cert_obj, is_need_to_request_cert);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_binding_status_obj, get_binding_status);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_logon_ID_obj, get_logon_ID);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(get_nick_name_obj, get_nick_name);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(unbinding_obj, unbinding);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(reset_all_obj, reset_all);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(enter_lpm_obj, enter_lpm);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(exit_lpm_obj, exit_lpm);
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(set_vendor_info_obj, set_vendor_info);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_product_type_obj, set_product_type);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(alipay_se_delete_obj, alipay_se_delete);
+
+
+/* 定义type的本地字典 */
+STATIC const mp_rom_map_elem_t ALIPAY_SE_locals_dict_table[] = {
+       { MP_OBJ_NEW_QSTR(MP_QSTR___name__),MP_ROM_QSTR(MP_QSTR_ALIPAY_SE) },
+    { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&alipay_se_delete_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_aid_code), MP_ROM_PTR(&get_aid_code_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_binding_code), MP_ROM_PTR(&get_binding_code_obj) },
+       { MP_ROM_QSTR(MP_QSTR_query_binding_result), MP_ROM_PTR(&query_binding_result_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_pay_code), MP_ROM_PTR(&get_paycode_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_collection_code), MP_ROM_PTR(&get_collectioncode_obj) },
+       { MP_ROM_QSTR(MP_QSTR_query_order_result), MP_ROM_PTR(&query_order_result_obj) },
+       { MP_ROM_QSTR(MP_QSTR_query_order_result_string), MP_ROM_PTR(&query_order_result_string_obj) },
+       { MP_ROM_QSTR(MP_QSTR_query_income_details), MP_ROM_PTR(&query_income_details_obj) },
+       { MP_ROM_QSTR(MP_QSTR_query_flow_break), MP_ROM_PTR(&query_flow_break_obj) },
+       { MP_ROM_QSTR(MP_QSTR_check_active_status), MP_ROM_PTR(&check_active_status_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_active_request), MP_ROM_PTR(&get_active_request_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_active_request_campt), MP_ROM_PTR(&get_active_request_campt_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_active_request_with_antchain), MP_ROM_PTR(&get_active_request_with_antchain_obj) },
+       { MP_ROM_QSTR(MP_QSTR_save_active_response), MP_ROM_PTR(&save_active_response_obj) },
+       { MP_ROM_QSTR(MP_QSTR_check_ecc_alg), MP_ROM_PTR(&check_ecc_alg_obj) },
+       { MP_ROM_QSTR(MP_QSTR_secure_get_auth_data), MP_ROM_PTR(&secure_get_auth_data_obj) },
+       { MP_ROM_QSTR(MP_QSTR_secure_rcv_dev_cert), MP_ROM_PTR(&secure_rcv_dev_cert_obj) },
+       { MP_ROM_QSTR(MP_QSTR_check_cert), MP_ROM_PTR(&is_need_to_request_cert_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_binding_status), MP_ROM_PTR(&get_binding_status_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_logon_ID), MP_ROM_PTR(&get_logon_ID_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_nick_name), MP_ROM_PTR(&get_nick_name_obj) },
+       { MP_ROM_QSTR(MP_QSTR_unbinding), MP_ROM_PTR(&unbinding_obj) },
+       { MP_ROM_QSTR(MP_QSTR_enter_lpm), MP_ROM_PTR(&enter_lpm_obj) },
+       { MP_ROM_QSTR(MP_QSTR_exit_lpm), MP_ROM_PTR(&exit_lpm_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_vendor_info), MP_ROM_PTR(&set_vendor_info_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_product_type), MP_ROM_PTR(&set_product_type_obj) },
+       { MP_ROM_QSTR(MP_QSTR_ADULT_WATCH), MP_ROM_INT(PRODUCT_TYPE_ADULT_WATCH) },
+       { MP_ROM_QSTR(MP_QSTR_ADULT_BRACELET), MP_ROM_INT(PRODUCT_TYPE_ADULT_BRACELET) },
+       { MP_ROM_QSTR(MP_QSTR_ADULT_CARD), MP_ROM_INT(PRODUCT_TYPE_ADULT_CARD) },
+       { MP_ROM_QSTR(MP_QSTR_CHILD_WATCH), MP_ROM_INT(PRODUCT_TYPE_CHILD_WATCH) },
+       { MP_ROM_QSTR(MP_QSTR_CHILD_BRACELET), MP_ROM_INT(PRODUCT_TYPE_CHILD_BRACELET) },
+       { MP_ROM_QSTR(MP_QSTR_STUDENT_CARD), MP_ROM_INT(PRODUCT_TYPE_STUDENT_CARD) },
+       { MP_ROM_QSTR(MP_QSTR_reset_all), MP_ROM_PTR(&reset_all_obj) },
+};
+
+/* 把ALIPAY_SE_locals_dict_table注册到ALIPAY_SE_locals_dict里面去 */
+STATIC MP_DEFINE_CONST_DICT(ALIPAY_SE_locals_dict, ALIPAY_SE_locals_dict_table);
+
+/* 定义mp_obj_type_t类型的结构体;注意这里和定义module使用的类型是不一样的 */
+const mp_obj_type_t ALIPAY_SE_type = {
+    .base={ &mp_type_type }, 
+    .name = MP_QSTR_ALIPAY_SE, //type类的name属性是放在这里定义,而不是放在DICT中
+    .make_new = ALIPAY_SE_make_new, //添加的make new属性
+    .locals_dict = (mp_obj_dict_t*)&ALIPAY_SE_locals_dict, //注册ALIPAY_SE_locals_dict
+};
+    
+#endif
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modecdh.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modecdh.c
new file mode 100644 (file)
index 0000000..498e869
--- /dev/null
@@ -0,0 +1,576 @@
+#include "py/builtin.h"
+#include "py/runtime.h"
+#include "py/mpconfig.h"
+#include "py/objstr.h"
+#include "py/obj.h"
+#include "py/stream.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#if MICROPY_PY_UCRYPTOLIB_ECDH
+
+#include "mbedtls/version.h"
+#include "mbedtls/platform.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/error.h"
+#include "mbedtls/md_internal.h"
+#include "mbedtls/asn1write.h"
+#include "mbedtls/ecdh.h"
+
+
+#include "helios_debug.h"
+
+#define QPY_ECDH_LOG(msg, ...)      custom_log("ECDH", msg, ##__VA_ARGS__)
+
+#define FORMAT_BINARY           0
+#define FORMAT_PEM              1
+#define FORMAT_DER              2
+
+typedef struct _mp_obj_ecdh_t {
+    mp_obj_base_t base;
+} mp_obj_ecdh_t;
+
+STATIC mp_obj_t ucryptolib_ecdh_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
+{
+       (void)args;
+    mp_arg_check_num(n_args, n_kw, 0, 1, false);
+    mp_obj_ecdh_t *ecdh_self = m_new_obj_with_finaliser(mp_obj_ecdh_t);
+    ecdh_self->base.type = type;
+
+    return MP_OBJ_FROM_PTR(ecdh_self);
+}
+
+STATIC NORETURN void mbedtls_raise_error(int err)
+{
+    // _mbedtls_ssl_send and _mbedtls_ssl_recv (below) turn positive error codes from the
+    // underlying socket into negative codes to pass them through mbedtls. Here we turn them
+    // positive again so they get interpreted as the OSError they really are. The
+    // cut-off of -256 is a bit hacky, sigh.
+    if (err < 0 && err > -256) {
+        mp_raise_OSError(-err);
+    }
+
+    #if defined(MBEDTLS_ERROR_C)
+    // Including mbedtls_strerror takes about 1.5KB due to the error strings.
+    // MBEDTLS_ERROR_C is the define used by mbedtls to conditionally include mbedtls_strerror.
+    // It is set/unset in the MBEDTLS_CONFIG_FILE which is defined in the Makefile.
+
+    // Try to allocate memory for the message
+    #define ERR_STR_MAX 80  // mbedtls_strerror truncates if it doesn't fit
+    mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);
+    byte *o_str_buf = m_new_maybe(byte, ERR_STR_MAX);
+    if (o_str == NULL || o_str_buf == NULL) {
+        mp_raise_OSError(err);
+    }
+
+    // print the error message into the allocated buffer
+    mbedtls_strerror(err, (char *)o_str_buf, ERR_STR_MAX);
+    size_t len = strlen((char *)o_str_buf);
+
+    // Put the exception object together
+    o_str->base.type = &mp_type_str;
+    o_str->data = o_str_buf;
+    o_str->len = len;
+    o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
+    // raise
+    mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)};
+    nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args));
+    #else
+    // mbedtls is compiled without error strings so we simply return the err number
+    mp_raise_OSError(err); // err is typically a large negative number
+    #endif
+}
+
+//ec_curves()
+STATIC mp_obj_t ucryptolib_ecdh_ecurves(mp_obj_t self_in)
+{
+       (void)self_in;
+    mp_obj_t curve_list = mp_obj_new_list(0, NULL);
+    
+    const mbedtls_ecp_curve_info *curve_info;
+    curve_info = mbedtls_ecp_curve_list();
+    while( ( ++curve_info )->name != NULL ){
+       mp_obj_list_append(curve_list, MP_OBJ_FROM_PTR(mp_obj_new_str(curve_info->name, strlen(curve_info->name))));
+    }
+
+    return curve_list;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(ucryptolib_ecdh_curves_obj, ucryptolib_ecdh_ecurves);
+
+//ec_curve_info("curve")
+STATIC mp_obj_t ucryptolib_ecdh_curve_info(mp_obj_t self_in, const mp_obj_t o_in)
+{
+       (void)self_in;
+    mp_check_self(mp_obj_is_str_or_bytes(o_in));
+    const char *curve = mp_obj_str_get_str(o_in);
+    const mbedtls_ecp_curve_info *curve_info;
+    if ((curve_info = mbedtls_ecp_curve_info_from_name(curve)) == NULL )
+    {
+       return mp_const_none;
+    }
+    mp_obj_t tuple[4] = {mp_obj_new_int(curve_info->grp_id), mp_obj_new_int(curve_info->tls_id),
+                         mp_obj_new_int(curve_info->bit_size), 
+                        mp_obj_new_str(curve_info->name, strlen(curve_info->name))};    
+    
+    return mp_obj_new_tuple(4, tuple);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(ucryptolib_ecdh_curve_info_obj, ucryptolib_ecdh_curve_info);
+
+#if 0
+int ec_priv_key_to_hex_string(mbedtls_ecp_keypair *key)
+{
+       unsigned char priv_hex[128] = {0};
+       int len = 0;
+
+       char priv_key_hex[2 * mbedtls_ecp_keypair_priv_len(&key) + 1];
+    // 将私钥转换为十六进制字符串
+    char *ret = mbedtls_mpi_write_binary(&key.d, priv_hex, sizeof(priv_hex));
+    if(ret == NULL) {
+        return -1;
+    }
+
+       QPY_ECDH_LOG("hex buf: %02x:%02x:%02x, hex_len=%d\n", priv_hex[0], priv_hex[1]. priv_hex[2], hex_len);
+ 
+    return 0;
+}
+
+static void dump_buf( const char *title, unsigned char *buf, size_t len )
+{
+    size_t i;
+       char hex_key[512] = {0};
+       const char *decode_code = "0123456789ABCDEF";
+    for( i = 0; i < len; i++ )
+        snprintf(&hex_key[i*2], 3, "%c%c", decode_code[buf[i] / 16], decode_code[buf[i] % 16] );
+    QPY_ECDH_LOG("%s: %s\n", title, hex_key);
+}
+static void dump_hex( const char *title, unsigned char *buf, size_t len )
+{
+    size_t i;
+       char hex_key[512] = {0};
+    for( i = 0; i < len; i++ )
+        snprintf(&hex_key[i*2], 3, "%02x", buf[i]);
+    QPY_ECDH_LOG("%s: %s\n", title, hex_key);
+}
+
+static void get_public_hex_key(mbedtls_ecp_keypair *hex_keypair)
+{
+       unsigned char hex_buf[128] = {0};
+       size_t hex_len = 0;
+       int ret = 0;
+
+       if( ( ret = mbedtls_ecp_point_write_binary( &hex_keypair->grp, &hex_keypair->Q, MBEDTLS_ECP_PF_UNCOMPRESSED,
+                                        &hex_len, hex_buf, sizeof( hex_buf ) ) ) != 0 ) {
+        return;
+    }
+       QPY_ECDH_LOG("pubkey len: %d\n", hex_len);
+       dump_buf("publickey", hex_buf, hex_len);
+       dump_hex("publickey_hex", hex_buf, hex_len);
+}
+static void get_private_hex_key(mbedtls_ecp_keypair *hex_keypair)
+{
+       unsigned char priv_key[32] = {0};
+       int ret = 0;
+       size_t privlen = mbedtls_mpi_size(&hex_keypair->d);
+       if( ( ret = mbedtls_mpi_write_binary(&hex_keypair->d, priv_key, privlen))) {
+        return;
+    }
+
+       QPY_ECDH_LOG("prikey len: %d\n", privlen);
+       dump_buf("prikey", priv_key, privlen);
+       dump_hex("prikey_hex", priv_key, privlen);
+}
+#endif
+
+static void get_rand_seed(uint32_t *seed)
+{
+       int i = 0;
+       for(i = 0; i < 2; i++) {
+               seed[i] = rand();
+       }
+}
+
+STATIC mp_obj_t ucryptolib_ecdh_genkey(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+       (void)n_args;
+       (void)kw_args;
+    const char *curve = mp_obj_str_get_str(args[1]);
+    const int format = mp_obj_get_int(args[2]);
+       if( format != FORMAT_PEM && format != FORMAT_DER ) return mp_const_none;
+       const mbedtls_ecp_curve_info *curve_info;
+    if ((curve_info = mbedtls_ecp_curve_info_from_name(curve)) == NULL ) {
+       mp_raise_ValueError(MP_ERROR_TEXT("ec curve not found"));
+    }
+    mbedtls_pk_context key;
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+
+    //init
+    int ret;
+    mbedtls_pk_init( &key );
+    mbedtls_ctr_drbg_init( &ctr_drbg );
+    mbedtls_entropy_init( &entropy );
+    int bits = curve_info->bit_size;
+    unsigned char output_buf[bits];
+        // Seed
+    byte seed[8] = {0};
+       get_rand_seed((uint32_t *)seed);
+    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, seed, sizeof(seed));
+    if (ret != 0) {
+        goto cleanup;
+    }
+    //Generate the key
+    if( ( ret = mbedtls_pk_setup( &key, mbedtls_pk_info_from_type( (mbedtls_pk_type_t) MBEDTLS_PK_ECKEY ) ) ) != 0 ){
+       goto cleanup;
+    }
+
+    ret = mbedtls_ecp_gen_key( (mbedtls_ecp_group_id) curve_info->grp_id,
+                                   mbedtls_pk_ec( key ),
+                                   mbedtls_ctr_drbg_random, &ctr_drbg );
+    if( ret != 0 ) {
+       goto cleanup;
+    }
+
+    size_t len = 0;
+       mp_obj_t pkey;
+    memset(output_buf, 0, bits);
+       if (format == FORMAT_PEM){
+       if( ( ret = mbedtls_pk_write_key_pem( &key, output_buf, sizeof(output_buf) )) != 0 ){
+               goto cleanup;
+       }
+               len = strlen( (char *) output_buf );
+               pkey = mp_obj_new_bytes(output_buf, len);
+       } else {
+               unsigned char *c = output_buf;
+               if( ( ret = mbedtls_pk_write_key_der( &key, output_buf, sizeof(output_buf) )) < 0 ){
+               goto cleanup;
+       }
+               len = ret;
+               c = output_buf + sizeof(output_buf) - len;
+               pkey = mp_obj_new_bytes(c, len);
+       }
+
+    // Export public key
+       mp_obj_t pubkey;
+    memset(output_buf, 0, bits);
+       if (format == FORMAT_PEM) {
+       if( ( ret = mbedtls_pk_write_pubkey_pem( &key, output_buf, sizeof(output_buf) )) != 0 ){
+               goto cleanup;
+       }
+               len = strlen( (char *) output_buf );
+               pubkey = mp_obj_new_bytes(output_buf, len);
+       } else {
+               unsigned char output_der[bits];
+               unsigned char *cder = output_der;
+               memset(output_der, 0, bits);
+               if( ( ret = mbedtls_pk_write_pubkey_der( &key, output_der, sizeof(output_der) )) < 0 ){
+               goto cleanup;
+       }
+               len = ret;
+               cder = output_der + sizeof(output_der) - len;
+               pubkey = mp_obj_new_bytes(cder, len);
+       }
+
+    mp_obj_t tuple[2] = {pkey, pubkey};
+
+    // Clean up
+    mbedtls_pk_free(&key);
+    mbedtls_ctr_drbg_free(&ctr_drbg);
+    mbedtls_entropy_free(&entropy);
+
+    return mp_obj_new_tuple(2, tuple);
+
+cleanup:
+       mbedtls_pk_free(&key);
+       mbedtls_ctr_drbg_free(&ctr_drbg);
+       mbedtls_entropy_free(&entropy);
+       mbedtls_raise_error(ret);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(ucryptolib_ecdh_genkey_obj, 0,  ucryptolib_ecdh_genkey);
+
+//hex exchange pem
+STATIC int convert_bin_pubkey(unsigned char *key_hex, size_t key_len, int to_format, const char *curve, unsigned char *public_key)
+{
+       const mbedtls_ecp_curve_info *curve_info;
+    if ((curve_info = mbedtls_ecp_curve_info_from_name(curve)) == NULL )
+    {
+       mp_raise_ValueError(MP_ERROR_TEXT("ec curve not found"));
+    }
+    mbedtls_pk_context key;
+
+    //init
+    int ret;
+    mbedtls_pk_init( &key );
+       size_t len = 0;
+
+       mbedtls_ecp_group_id group_id = curve_info->grp_id;
+
+    //Generate the key
+    if( ( ret = mbedtls_pk_setup( &key, mbedtls_pk_info_from_type( (mbedtls_pk_type_t) MBEDTLS_PK_ECKEY ) ) ) != 0 ){
+       goto exchange_cleanup;
+    }
+
+       if( mbedtls_ecp_group_load(&mbedtls_pk_ec(key)->grp, group_id) != 0 )
+       {
+       QPY_ECDH_LOG("Failed to load elliptic curve parameters.\n");
+       goto exchange_cleanup;
+       }
+
+       ret = mbedtls_ecp_point_read_binary(&mbedtls_pk_ec(key)->grp, &mbedtls_pk_ec(key)->Q, (const unsigned char *) key_hex, key_len);
+       if(ret != 0) {
+        QPY_ECDH_LOG("mbedtls_ecp_point_read_binary returned -0x%04x\n", -ret);
+        goto exchange_cleanup;
+    }
+
+       if ( to_format == FORMAT_PEM ) {
+       if( ( ret = mbedtls_pk_write_pubkey_pem( &key, public_key, 512) ) != 0 ){
+               goto exchange_cleanup;
+       }
+               len = strlen((char *)public_key);
+       } else {
+               if( ( ret = mbedtls_pk_write_pubkey_der( &key, public_key, 512) ) < 0 ){
+               goto exchange_cleanup;
+       }
+               len = ret;
+       }
+
+    // Clean up
+    mbedtls_pk_free(&key);
+    return len;
+
+exchange_cleanup:
+       mbedtls_pk_free(&key);
+       mbedtls_raise_error(ret);
+}
+
+//hex exchange pem
+STATIC mp_obj_t ucryptolib_ecdh_convert_pubkey(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+       (void)kw_args;
+       size_t key_len;
+       byte *pkey = (byte *)mp_obj_str_get_data(args[1], &key_len);
+       int from_format = mp_obj_get_int(args[2]);
+       int to_format = mp_obj_get_int(args[3]);
+       
+       unsigned char public_key[512] = {0};
+       size_t len = 0;
+       int ret = 0;
+       if( from_format == to_format ) {
+               return args[1];
+       }
+
+       if ( from_format == 0 ) {
+               if ( n_args < 5 ) return mp_const_none;
+               const char *curve = mp_obj_str_get_str(args[4]);
+               ret = convert_bin_pubkey(pkey, key_len, to_format, curve, public_key);
+               len = ret;
+               return mp_obj_new_bytes(public_key, len);
+       } else if ( from_format == 1 ) {
+               key_len = key_len + 1;
+       }
+
+       mbedtls_pk_context key;
+    mbedtls_pk_init( &key );
+       ret = mbedtls_pk_parse_public_key(&key, pkey, key_len);
+    if (ret != 0) {
+           //ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors
+           QPY_ECDH_LOG("mbedtls_pk_parse_public_key failed\n");
+           goto convert_cleanup;
+    }
+
+       if ( to_format == FORMAT_PEM ) {
+       if( ( ret = mbedtls_pk_write_pubkey_pem( &key, public_key, sizeof(public_key) )) != 0 ){
+               goto convert_cleanup;
+       }
+               len = strlen( (char *) public_key );
+       } else if ( to_format == FORMAT_DER ) {
+               if( ( ret = mbedtls_pk_write_pubkey_der( &key, public_key, sizeof(public_key) )) < 0 ){
+               goto convert_cleanup;
+       }
+               len = ret;
+       } else {
+               mbedtls_ecp_keypair *hex_keypair = mbedtls_pk_ec( key );
+           if( ( ret = mbedtls_ecp_point_write_binary( &hex_keypair->grp, &hex_keypair->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &len, public_key, sizeof( public_key ) ) ) != 0 ) {
+                       goto convert_cleanup;
+               }
+    }
+       
+       mbedtls_pk_free(&key);
+       return mp_obj_new_bytes(public_key, len);
+convert_cleanup:
+       mbedtls_pk_free(&key);
+       mbedtls_raise_error(ret);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(ucryptolib_ecdh_convert_pubkey_obj, 4,ucryptolib_ecdh_convert_pubkey);
+
+
+//Derive public key
+STATIC mp_obj_t ucryptolib_ecdh_get_pubkey(mp_obj_t self_in, const mp_obj_t key_in, const mp_obj_t format)
+{
+       (void)self_in;
+    mp_check_self(mp_obj_is_str_or_bytes(key_in));
+   
+    int ret;
+       int fmt = mp_obj_get_int(format);
+       if( fmt != FORMAT_PEM && fmt != FORMAT_DER ) return mp_const_none;
+    mbedtls_pk_context key;
+    mbedtls_pk_init( &key );
+
+    //Parse private key
+    size_t key_len;
+    byte *pkey = (byte *)mp_obj_str_get_data(key_in, &key_len);
+    unsigned char output_buf[key_len];
+
+       if (fmt == FORMAT_PEM) {
+               key_len = key_len + 1;
+       }
+
+    ret = mbedtls_pk_parse_key(&key, pkey, key_len, NULL, 0);
+    if (ret != 0) {
+           goto cleanup;
+    }
+
+       mp_obj_t pubkey;
+    size_t len = 0;
+    memset(output_buf, 0, key_len);
+       if ( fmt == FORMAT_PEM ) {
+       if( ( ret = mbedtls_pk_write_pubkey_pem( &key, output_buf, sizeof(output_buf) )) != 0 ){
+               goto cleanup;
+       }
+               len = strlen( (char *) output_buf );
+               pubkey = mp_obj_new_bytes(output_buf, len);
+       } else {
+               // mp_raise_ValueError(MP_ERROR_TEXT("NotImplementedError: DER format"));
+               unsigned char output_der[key_len];
+               unsigned char *cder = output_der;
+               memset(output_der, 0, key_len);
+
+               if( ( ret = mbedtls_pk_write_pubkey_der( &key, output_der, sizeof(output_der) )) < 0 ){
+               goto cleanup;
+       }
+               len = ret;
+               cder = output_der + sizeof(output_der) - len;
+               pubkey = mp_obj_new_bytes(cder, len);
+       }
+    
+    // Clean up
+    mbedtls_pk_free(&key); 
+
+
+    return pubkey;
+
+cleanup:
+       mbedtls_pk_free(&key);
+       mbedtls_raise_error(ret);
+       
+}
+MP_DEFINE_CONST_FUN_OBJ_3(ucryptolib_ecdh_get_pubkey_obj, ucryptolib_ecdh_get_pubkey);
+
+//Derive public key
+STATIC mp_obj_t ucryptolib_ecdh_exchange(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+       (void)n_args;
+       (void)kw_args;
+
+    int ret;
+       int fmt = mp_obj_get_int(args[3]);
+       if( fmt != FORMAT_PEM && fmt != FORMAT_DER ) return mp_const_none;
+    mbedtls_pk_context prikey;
+       mbedtls_pk_context pubkey;
+       mbedtls_entropy_context entropy;
+       mbedtls_ctr_drbg_context ctr_drbg;
+       mbedtls_mpi z;
+       unsigned char share_buffer[32] = {0};
+       
+    //Parse private key
+    size_t prikey_len;
+    byte *prikey_pem = (byte *)mp_obj_str_get_data(args[1], &prikey_len);
+       size_t pubkey_len;
+       byte *pubkey_kem = (byte *)mp_obj_str_get_data(args[2], &pubkey_len);
+
+       if (fmt == FORMAT_PEM) {
+               prikey_len = prikey_len + 1;
+               pubkey_len = pubkey_len + 1;
+       }
+
+       mbedtls_pk_init( &pubkey );
+    mbedtls_ctr_drbg_init( &ctr_drbg );
+    mbedtls_entropy_init( &entropy );
+
+       mbedtls_pk_init( &prikey );
+       mbedtls_pk_init( &pubkey );
+       mbedtls_mpi_init(&z);
+        // Seed
+    byte seed[8] = {0};
+       get_rand_seed((uint32_t *)seed);
+    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, seed, sizeof(seed));
+    if (ret != 0) {
+        goto share_key_cleanup;
+    }
+
+       ret = mbedtls_pk_parse_key(&prikey, prikey_pem, prikey_len, NULL, 0);
+    if (ret != 0) {
+           goto share_key_cleanup;
+    }
+
+       ret = mbedtls_pk_parse_public_key(&pubkey, pubkey_kem, pubkey_len);
+    if (ret != 0) {
+           //ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors
+           QPY_ECDH_LOG("mbedtls_pk_parse_public_key failed\n");
+           goto share_key_cleanup;
+    }
+
+       ret = mbedtls_ecdh_compute_shared(&mbedtls_pk_ec(pubkey)->grp, &z, &mbedtls_pk_ec(pubkey)->Q, &mbedtls_pk_ec(prikey)->d, mbedtls_ctr_drbg_random, &ctr_drbg);
+       if (ret != 0) {
+               QPY_ECDH_LOG("ecdh share failed\n");
+               goto share_key_cleanup;
+       }
+
+    mbedtls_mpi_write_binary(&z, share_buffer, sizeof(share_buffer));
+
+    // Clean up
+    mbedtls_mpi_free(&z);
+       mbedtls_pk_free(&prikey);
+       mbedtls_pk_free(&pubkey);
+       mbedtls_ctr_drbg_free(&ctr_drbg);
+       mbedtls_entropy_free(&entropy);
+
+    return mp_obj_new_bytes(share_buffer, sizeof(share_buffer));
+
+share_key_cleanup:
+       mbedtls_mpi_free(&z);
+       mbedtls_pk_free(&prikey);
+       mbedtls_pk_free(&pubkey);
+       mbedtls_ctr_drbg_free(&ctr_drbg);
+       mbedtls_entropy_free(&entropy);
+       mbedtls_raise_error(ret);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(ucryptolib_ecdh_exchange_obj, 4,ucryptolib_ecdh_exchange);
+
+STATIC const mp_rom_map_elem_t ucryptolib_ecdh_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ecdhs) },
+    { MP_ROM_QSTR(MP_QSTR_curves), MP_ROM_PTR(&ucryptolib_ecdh_curves_obj) },
+    { MP_ROM_QSTR(MP_QSTR_curve_info), MP_ROM_PTR(&ucryptolib_ecdh_curve_info_obj) },
+    { MP_ROM_QSTR(MP_QSTR_gen_key), MP_ROM_PTR(&ucryptolib_ecdh_genkey_obj) },
+    { MP_ROM_QSTR(MP_QSTR_get_pubkey), MP_ROM_PTR(&ucryptolib_ecdh_get_pubkey_obj) },
+    { MP_ROM_QSTR(MP_QSTR_convert_pubkey), MP_ROM_PTR(&ucryptolib_ecdh_convert_pubkey_obj) },
+    { MP_ROM_QSTR(MP_QSTR_exchange), MP_ROM_PTR(&ucryptolib_ecdh_exchange_obj) },
+       { MP_ROM_QSTR(MP_QSTR_FORMAT_PEM), MP_ROM_INT(FORMAT_PEM) },
+       { MP_ROM_QSTR(MP_QSTR_FORMAT_DER), MP_ROM_INT(FORMAT_DER) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ucryptolib_ecdh_locals_dict, ucryptolib_ecdh_locals_dict_table);
+
+const mp_obj_type_t ucryptolib_ecdh_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_ecdh,
+    .make_new = ucryptolib_ecdh_make_new,
+    .locals_dict = (void *)&ucryptolib_ecdh_locals_dict,
+};
+
+#endif
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modecdsa.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modecdsa.c
new file mode 100644 (file)
index 0000000..9a0e5ee
--- /dev/null
@@ -0,0 +1,735 @@
+#include "py/builtin.h"
+#include "py/runtime.h"
+#include "py/mpconfig.h"
+#include "py/objstr.h"
+#include "py/obj.h"
+#include "py/stream.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#if MICROPY_PY_UCRYPTOLIB_ECDSA
+
+#include "mbedtls/version.h"
+#include "mbedtls/platform.h"
+#include "mbedtls/ecdsa.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/error.h"
+#include "mbedtls/md_internal.h"
+#include "mbedtls/asn1write.h"
+
+#include "helios_debug.h"
+
+#define QPY_ECDSA_LOG(msg, ...)      custom_log("ECDSA", msg, ##__VA_ARGS__)
+
+#define FORMAT_BINARY           0
+#define FORMAT_PEM              1
+#define FORMAT_DER              2
+
+typedef struct _mp_obj_ecdsa_t {
+    mp_obj_base_t base;
+} mp_obj_ecdsa_t;
+
+STATIC mp_obj_t ucryptolib_ecdsa_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
+{
+       (void)args;
+    mp_arg_check_num(n_args, n_kw, 0, 1, false);
+    mp_obj_ecdsa_t *ecdsa_self = m_new_obj_with_finaliser(mp_obj_ecdsa_t);
+    ecdsa_self->base.type = type;
+
+    return MP_OBJ_FROM_PTR(ecdsa_self);
+}
+
+STATIC NORETURN void mbedtls_raise_error(int err)
+{
+    // _mbedtls_ssl_send and _mbedtls_ssl_recv (below) turn positive error codes from the
+    // underlying socket into negative codes to pass them through mbedtls. Here we turn them
+    // positive again so they get interpreted as the OSError they really are. The
+    // cut-off of -256 is a bit hacky, sigh.
+    if (err < 0 && err > -256) {
+        mp_raise_OSError(-err);
+    }
+
+    #if defined(MBEDTLS_ERROR_C)
+    // Including mbedtls_strerror takes about 1.5KB due to the error strings.
+    // MBEDTLS_ERROR_C is the define used by mbedtls to conditionally include mbedtls_strerror.
+    // It is set/unset in the MBEDTLS_CONFIG_FILE which is defined in the Makefile.
+
+    // Try to allocate memory for the message
+    #define ERR_STR_MAX 80  // mbedtls_strerror truncates if it doesn't fit
+    mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);
+    byte *o_str_buf = m_new_maybe(byte, ERR_STR_MAX);
+    if (o_str == NULL || o_str_buf == NULL) {
+        mp_raise_OSError(err);
+    }
+
+    // print the error message into the allocated buffer
+    mbedtls_strerror(err, (char *)o_str_buf, ERR_STR_MAX);
+    size_t len = strlen((char *)o_str_buf);
+
+    // Put the exception object together
+    o_str->base.type = &mp_type_str;
+    o_str->data = o_str_buf;
+    o_str->len = len;
+    o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
+    // raise
+    mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)};
+    nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args));
+    #else
+    // mbedtls is compiled without error strings so we simply return the err number
+    mp_raise_OSError(err); // err is typically a large negative number
+    #endif
+}
+
+//ec_curves()
+STATIC mp_obj_t ucryptolib_ecdsa_ecurves(mp_obj_t self_in)
+{
+       (void)self_in;
+    mp_obj_t curve_list = mp_obj_new_list(0, NULL);
+    
+    const mbedtls_ecp_curve_info *curve_info;
+    curve_info = mbedtls_ecp_curve_list();
+    while( ( ++curve_info )->name != NULL ){
+       mp_obj_list_append(curve_list, MP_OBJ_FROM_PTR(mp_obj_new_str(curve_info->name, strlen(curve_info->name))));
+    }
+
+    return curve_list;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(ucryptolib_ecdsa_curves_obj, ucryptolib_ecdsa_ecurves);
+
+//ec_curve_info("curve")
+STATIC mp_obj_t ucryptolib_ecdsa_curve_info(mp_obj_t self_in, const mp_obj_t o_in)
+{
+       (void)self_in;
+    mp_check_self(mp_obj_is_str_or_bytes(o_in));
+    const char *curve = mp_obj_str_get_str(o_in);
+    const mbedtls_ecp_curve_info *curve_info;
+    if ((curve_info = mbedtls_ecp_curve_info_from_name(curve)) == NULL )
+    {
+       return mp_const_none;
+    }
+    mp_obj_t tuple[4] = {mp_obj_new_int(curve_info->grp_id), mp_obj_new_int(curve_info->tls_id),
+                         mp_obj_new_int(curve_info->bit_size), 
+                        mp_obj_new_str(curve_info->name, strlen(curve_info->name))};    
+    
+    return mp_obj_new_tuple(4, tuple);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(ucryptolib_ecdsa_curve_info_obj, ucryptolib_ecdsa_curve_info);
+
+#if 0
+int ec_priv_key_to_hex_string(mbedtls_ecp_keypair *key)
+{
+       unsigned char priv_hex[128] = {0};
+       int len = 0;
+
+       char priv_key_hex[2 * mbedtls_ecp_keypair_priv_len(&key) + 1];
+    // 将私钥转换为十六进制字符串
+    char *ret = mbedtls_mpi_write_binary(&key.d, priv_hex, sizeof(priv_hex));
+    if(ret == NULL) {
+        return -1;
+    }
+
+       QPY_ECDSA_LOG("hex buf: %02x:%02x:%02x, hex_len=%d\n", priv_hex[0], priv_hex[1]. priv_hex[2], hex_len);
+ 
+    return 0;
+}
+
+static void dump_buf( const char *title, unsigned char *buf, size_t len )
+{
+    size_t i;
+       char hex_key[512] = {0};
+       const char *decode_code = "0123456789ABCDEF";
+    for( i = 0; i < len; i++ )
+        snprintf(&hex_key[i*2], 3, "%c%c", decode_code[buf[i] / 16], decode_code[buf[i] % 16] );
+    QPY_ECDSA_LOG("%s: %s\n", title, hex_key);
+}
+static void dump_hex( const char *title, unsigned char *buf, size_t len )
+{
+    size_t i;
+       char hex_key[512] = {0};
+    for( i = 0; i < len; i++ )
+        snprintf(&hex_key[i*2], 3, "%02x", buf[i]);
+    QPY_ECDSA_LOG("%s: %s\n", title, hex_key);
+}
+
+static void get_public_hex_key(mbedtls_ecp_keypair *hex_keypair)
+{
+       unsigned char hex_buf[128] = {0};
+       size_t hex_len = 0;
+       int ret = 0;
+
+       if( ( ret = mbedtls_ecp_point_write_binary( &hex_keypair->grp, &hex_keypair->Q, MBEDTLS_ECP_PF_UNCOMPRESSED,
+                                        &hex_len, hex_buf, sizeof( hex_buf ) ) ) != 0 ) {
+        return;
+    }
+       QPY_ECDSA_LOG("pubkey len: %d\n", hex_len);
+       dump_buf("publickey", hex_buf, hex_len);
+       dump_hex("publickey_hex", hex_buf, hex_len);
+}
+static void get_private_hex_key(mbedtls_ecp_keypair *hex_keypair)
+{
+       unsigned char priv_key[32] = {0};
+       int ret = 0;
+       size_t privlen = mbedtls_mpi_size(&hex_keypair->d);
+       if( ( ret = mbedtls_mpi_write_binary(&hex_keypair->d, priv_key, privlen))) {
+        return;
+    }
+
+       QPY_ECDSA_LOG("prikey len: %d\n", privlen);
+       dump_buf("prikey", priv_key, privlen);
+       dump_hex("prikey_hex", priv_key, privlen);
+}
+#endif
+
+static void get_rand_seed(uint32_t *seed)
+{
+       int i = 0;
+       for(i = 0; i < 2; i++) {
+               seed[i] = rand();
+       }
+}
+
+STATIC mp_obj_t ucryptolib_ecdsa_genkey(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+       (void)n_args;
+       (void)kw_args;
+    const char *curve = mp_obj_str_get_str(args[1]);
+    const int format = mp_obj_get_int(args[2]);
+       if( format != FORMAT_PEM && format != FORMAT_DER ) return mp_const_none;
+       const mbedtls_ecp_curve_info *curve_info;
+    if ((curve_info = mbedtls_ecp_curve_info_from_name(curve)) == NULL ) {
+       mp_raise_ValueError(MP_ERROR_TEXT("ec curve not found"));
+    }
+    mbedtls_pk_context key;
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+
+    //init
+    int ret;
+    mbedtls_pk_init( &key );
+    mbedtls_ctr_drbg_init( &ctr_drbg );
+    mbedtls_entropy_init( &entropy );
+    int bits = curve_info->bit_size;
+    unsigned char output_buf[bits];
+        // Seed
+    byte seed[8] = {0};
+       get_rand_seed((uint32_t *)seed);
+    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, seed, sizeof(seed));
+    if (ret != 0) {
+        goto cleanup;
+    }
+    //Generate the key
+    if( ( ret = mbedtls_pk_setup( &key, mbedtls_pk_info_from_type( (mbedtls_pk_type_t) MBEDTLS_PK_ECKEY ) ) ) != 0 ){
+       goto cleanup;
+    }
+
+    ret = mbedtls_ecp_gen_key( (mbedtls_ecp_group_id) curve_info->grp_id,
+                                   mbedtls_pk_ec( key ),
+                                   mbedtls_ctr_drbg_random, &ctr_drbg );
+    if( ret != 0 ) {
+       goto cleanup;
+    }
+
+    size_t len = 0;
+       mp_obj_t pkey;
+    memset(output_buf, 0, bits);
+       if (format == FORMAT_PEM){
+       if( ( ret = mbedtls_pk_write_key_pem( &key, output_buf, sizeof(output_buf) )) != 0 ){
+               goto cleanup;
+       }
+               len = strlen( (char *) output_buf );
+               pkey = mp_obj_new_bytes(output_buf, len);
+       } else {
+               unsigned char *c = output_buf;
+               if( ( ret = mbedtls_pk_write_key_der( &key, output_buf, sizeof(output_buf) )) < 0 ){
+               goto cleanup;
+       }
+               len = ret;
+               c = output_buf + sizeof(output_buf) - len;
+               pkey = mp_obj_new_bytes(c, len);
+       }
+
+    // Export public key
+       mp_obj_t pubkey;
+    memset(output_buf, 0, bits);
+       if (format == FORMAT_PEM) {
+       if( ( ret = mbedtls_pk_write_pubkey_pem( &key, output_buf, sizeof(output_buf) )) != 0 ){
+               goto cleanup;
+       }
+               len = strlen( (char *) output_buf );
+               pubkey = mp_obj_new_bytes(output_buf, len);
+       } else {
+               unsigned char output_der[bits];
+               unsigned char *cder = output_der;
+               memset(output_der, 0, bits);
+               if( ( ret = mbedtls_pk_write_pubkey_der( &key, output_der, sizeof(output_der) )) < 0 ){
+               goto cleanup;
+       }
+               len = ret;
+               cder = output_der + sizeof(output_der) - len;
+               pubkey = mp_obj_new_bytes(cder, len);
+       }
+
+    mp_obj_t tuple[2] = {pkey, pubkey};
+
+    // Clean up
+    mbedtls_pk_free(&key);
+    mbedtls_ctr_drbg_free(&ctr_drbg);
+    mbedtls_entropy_free(&entropy);
+
+    return mp_obj_new_tuple(2, tuple);
+
+cleanup:
+       mbedtls_pk_free(&key);
+       mbedtls_ctr_drbg_free(&ctr_drbg);
+       mbedtls_entropy_free(&entropy);
+       mbedtls_raise_error(ret);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(ucryptolib_ecdsa_genkey_obj, 0,  ucryptolib_ecdsa_genkey);
+
+//hex exchange pem
+STATIC int convert_bin_pubkey(unsigned char *key_hex, size_t key_len, int to_format, const char *curve, unsigned char *public_key)
+{
+       const mbedtls_ecp_curve_info *curve_info;
+    if ((curve_info = mbedtls_ecp_curve_info_from_name(curve)) == NULL )
+    {
+       mp_raise_ValueError(MP_ERROR_TEXT("ec curve not found"));
+    }
+    mbedtls_pk_context key;
+
+    //init
+    int ret;
+    mbedtls_pk_init( &key );
+       size_t len = 0;
+
+       mbedtls_ecp_group_id group_id = curve_info->grp_id;
+
+    //Generate the key
+    if( ( ret = mbedtls_pk_setup( &key, mbedtls_pk_info_from_type( (mbedtls_pk_type_t) MBEDTLS_PK_ECKEY ) ) ) != 0 ){
+       goto exchange_cleanup;
+    }
+
+       if( mbedtls_ecp_group_load(&mbedtls_pk_ec(key)->grp, group_id) != 0 )
+       {
+       QPY_ECDSA_LOG("Failed to load elliptic curve parameters.\n");
+       goto exchange_cleanup;
+       }
+
+       ret = mbedtls_ecp_point_read_binary(&mbedtls_pk_ec(key)->grp, &mbedtls_pk_ec(key)->Q, (const unsigned char *) key_hex, key_len);
+       if(ret != 0) {
+        QPY_ECDSA_LOG("mbedtls_ecp_point_read_binary returned -0x%04x\n", -ret);
+        goto exchange_cleanup;
+    }
+
+       if ( to_format == FORMAT_PEM ) {
+       if( ( ret = mbedtls_pk_write_pubkey_pem( &key, public_key, 512) ) != 0 ){
+               goto exchange_cleanup;
+       }
+               len = strlen((char *)public_key);
+       } else {
+               if( ( ret = mbedtls_pk_write_pubkey_der( &key, public_key, 512) ) < 0 ){
+               goto exchange_cleanup;
+       }
+               len = ret;
+       }
+
+    // Clean up
+    mbedtls_pk_free(&key);
+    return len;
+
+exchange_cleanup:
+       mbedtls_pk_free(&key);
+       mbedtls_raise_error(ret);
+}
+
+//hex exchange pem
+STATIC mp_obj_t ucryptolib_ecdsa_convert_pubkey(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+       (void)kw_args;
+       size_t key_len;
+       byte *pkey = (byte *)mp_obj_str_get_data(args[1], &key_len);
+       int from_format = mp_obj_get_int(args[2]);
+       int to_format = mp_obj_get_int(args[3]);
+       
+       unsigned char public_key[512] = {0};
+       size_t len = 0;
+       int ret = 0;
+       if( from_format == to_format ) {
+               return args[1];
+       }
+
+       if ( from_format == 0 ) {
+               if ( n_args < 5 ) return mp_const_none;
+               const char *curve = mp_obj_str_get_str(args[4]);
+               ret = convert_bin_pubkey(pkey, key_len, to_format, curve, public_key);
+               len = ret;
+               return mp_obj_new_bytes(public_key, len);
+       } else if ( from_format == 1 ) {
+               key_len = key_len + 1;
+       }
+
+       mbedtls_pk_context key;
+    mbedtls_pk_init( &key );
+       ret = mbedtls_pk_parse_public_key(&key, pkey, key_len);
+    if (ret != 0) {
+           //ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors
+           QPY_ECDSA_LOG("mbedtls_pk_parse_public_key failed\n");
+           goto convert_cleanup;
+    }
+
+       if ( to_format == FORMAT_PEM ) {
+       if( ( ret = mbedtls_pk_write_pubkey_pem( &key, public_key, sizeof(public_key) )) != 0 ){
+               goto convert_cleanup;
+       }
+               len = strlen( (char *) public_key );
+       } else if ( to_format == FORMAT_DER ) {
+               if( ( ret = mbedtls_pk_write_pubkey_der( &key, public_key, sizeof(public_key) )) < 0 ){
+               goto convert_cleanup;
+       }
+               len = ret;
+       } else {
+               mbedtls_ecp_keypair *hex_keypair = mbedtls_pk_ec( key );
+           if( ( ret = mbedtls_ecp_point_write_binary( &hex_keypair->grp, &hex_keypair->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &len, public_key, sizeof( public_key ) ) ) != 0 ) {
+                       goto convert_cleanup;
+               }
+    }
+       
+       mbedtls_pk_free(&key);
+       return mp_obj_new_bytes(public_key, len);
+convert_cleanup:
+       mbedtls_pk_free(&key);
+       mbedtls_raise_error(ret);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(ucryptolib_ecdsa_convert_pubkey_obj, 4,ucryptolib_ecdsa_convert_pubkey);
+
+
+//Derive public key
+STATIC mp_obj_t ucryptolib_ecdsa_get_pubkey(mp_obj_t self_in, const mp_obj_t key_in, const mp_obj_t format)
+{
+       (void)self_in;
+    mp_check_self(mp_obj_is_str_or_bytes(key_in));
+   
+    int ret;
+       int fmt = mp_obj_get_int(format);
+       if( fmt != FORMAT_PEM && fmt != FORMAT_DER ) return mp_const_none;
+    mbedtls_pk_context key;
+    mbedtls_pk_init( &key );
+
+    //Parse private key
+    size_t key_len;
+    byte *pkey = (byte *)mp_obj_str_get_data(key_in, &key_len);
+    unsigned char output_buf[key_len];
+
+       if (fmt == FORMAT_PEM) {
+               key_len = key_len + 1;
+       }
+
+    ret = mbedtls_pk_parse_key(&key, pkey, key_len, NULL, 0);
+    if (ret != 0) {
+           goto cleanup;
+    }
+
+       mp_obj_t pubkey;
+    size_t len = 0;
+    memset(output_buf, 0, key_len);
+       if ( fmt == FORMAT_PEM ) {
+       if( ( ret = mbedtls_pk_write_pubkey_pem( &key, output_buf, sizeof(output_buf) )) != 0 ){
+               goto cleanup;
+       }
+               len = strlen( (char *) output_buf );
+               pubkey = mp_obj_new_bytes(output_buf, len);
+       } else {
+               // mp_raise_ValueError(MP_ERROR_TEXT("NotImplementedError: DER format"));
+               unsigned char output_der[key_len];
+               unsigned char *cder = output_der;
+               memset(output_der, 0, key_len);
+
+               if( ( ret = mbedtls_pk_write_pubkey_der( &key, output_der, sizeof(output_der) )) < 0 ){
+               goto cleanup;
+       }
+               len = ret;
+               cder = output_der + sizeof(output_der) - len;
+               pubkey = mp_obj_new_bytes(cder, len);
+       }
+    
+    // Clean up
+    mbedtls_pk_free(&key); 
+
+
+    return pubkey;
+
+cleanup:
+       mbedtls_pk_free(&key);
+       mbedtls_raise_error(ret);
+       
+}
+MP_DEFINE_CONST_FUN_OBJ_3(ucryptolib_ecdsa_get_pubkey_obj, ucryptolib_ecdsa_get_pubkey);
+
+// Sign
+STATIC mp_obj_t ucryptolib_ecdsa_key_sign(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+       (void)kw_args;
+       int fmt = mp_obj_get_int(args[3]);
+       if( fmt != FORMAT_PEM && fmt != FORMAT_DER ) return mp_const_none;
+
+    mbedtls_pk_context key;
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+
+       mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
+
+       if ( n_args >= 5 ) {
+               const char *md_name_str = (const char *)mp_obj_str_get_str(args[4]);
+               const mbedtls_md_info_t *md_info = mbedtls_md_info_from_string(md_name_str);
+               md_type = md_info->type;
+       }
+    //init 
+    int ret;
+    unsigned char hash[32];
+    unsigned char buf[MBEDTLS_ECDSA_MAX_LEN];
+    size_t olen = 0;
+
+       //Parse private key
+    size_t key_len;
+    byte *pkey = (byte *)mp_obj_str_get_data(args[1], &key_len);
+       if (fmt == FORMAT_PEM) {
+               key_len = key_len + 1;
+       }
+       
+    mbedtls_pk_init( &key );
+    mbedtls_ctr_drbg_init( &ctr_drbg );
+    mbedtls_entropy_init( &entropy );
+    // Seed
+    byte seed[8] = {0};
+       get_rand_seed((uint32_t *)seed);
+    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, seed, sizeof(seed));
+    if (ret != 0) {
+        goto cleanup;
+    }
+
+    ret = mbedtls_pk_parse_key(&key, pkey, key_len, NULL, 0);
+    if (ret != 0) {
+           goto cleanup;
+    }
+
+    //Parse data
+    size_t data_len;
+    const byte *data = (const byte *)mp_obj_str_get_data(args[2], &data_len);
+
+    // hash of data
+    if( ( ret = mbedtls_md( mbedtls_md_info_from_type( md_type ), data, data_len, hash ) ) != 0 ){
+       goto cleanup;
+    }
+
+    //Sign data hash
+    if( ( ret = mbedtls_pk_sign( &key, md_type, hash, 0, buf, &olen,
+                         mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 ){
+       goto cleanup;
+    }
+
+    // Clean up
+    mbedtls_pk_free(&key);
+    mbedtls_ctr_drbg_free(&ctr_drbg);
+    mbedtls_entropy_free(&entropy);
+
+    return mp_obj_new_bytes(buf, olen);
+       
+cleanup:
+       mbedtls_pk_free(&key);
+       mbedtls_ctr_drbg_free(&ctr_drbg);
+       mbedtls_entropy_free(&entropy);
+       mbedtls_raise_error(ret);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(ucryptolib_ecdsa_key_sign_obj, 4, ucryptolib_ecdsa_key_sign);
+
+// Verify
+STATIC mp_obj_t ucryptolib_ecdsa_key_verify(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+       (void)kw_args;
+    mbedtls_pk_context key;
+    //init 
+    int ret;
+       mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
+    unsigned char hash[32];
+    mbedtls_pk_init( &key );
+    //Parse public key
+    size_t key_len;
+    const byte *pkey = (const byte *)mp_obj_str_get_data(args[1], &key_len);
+       
+    //Parse data
+    size_t data_len;
+    const byte *data = (const byte *)mp_obj_str_get_data(args[2], &data_len);
+
+    //Parse sig
+    size_t sig_len;
+    const byte *sig = (const byte *)mp_obj_str_get_data(args[3], &sig_len);
+
+       int fmt = mp_obj_get_int(args[4]);
+       if( fmt != FORMAT_PEM && fmt != FORMAT_DER ) return mp_const_none;
+
+       if ( fmt == FORMAT_PEM ) {
+               key_len = key_len + 1;
+       }
+
+       if ( n_args >= 6 ) {
+               const char *md_name_str = (const char *)mp_obj_str_get_str(args[5]);
+               const mbedtls_md_info_t *md_info = mbedtls_md_info_from_string(md_name_str);\
+               md_type = md_info->type;
+       }
+
+    ret = mbedtls_pk_parse_public_key(&key, pkey, key_len);
+    if (ret != 0) {
+           //ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors
+           goto cleanup;
+    }
+
+    // SHA-256 hash of data
+    if( ( ret = mbedtls_md( mbedtls_md_info_from_type( md_type ), data, data_len, hash ) ) != 0 ){
+       goto cleanup;
+    }
+
+    //Verify data hash
+    if( ( ret = mbedtls_pk_verify( &key, md_type, hash, 0, sig, sig_len) != 0 )){
+           goto cleanup;
+    }
+
+    // Clean up
+    mbedtls_pk_free(&key); 
+    
+    return mp_const_true;
+       
+cleanup:
+       mbedtls_pk_free(&key);
+    mbedtls_raise_error(ret);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(ucryptolib_ecdsa_key_verify_obj, 5, ucryptolib_ecdsa_key_verify);
+
+//Derive public key
+STATIC mp_obj_t ucryptolib_ecdsa_convert_sig(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+       (void)kw_args;
+       mbedtls_mpi r, s;
+       mbedtls_mpi_init( &r );
+    mbedtls_mpi_init( &s );
+       unsigned char buf[MBEDTLS_ECDSA_MAX_LEN];
+       int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+       if( n_args == 2 ) {
+               size_t sig_len;
+       const byte *sig = (const byte *)mp_obj_str_get_data(args[1], &sig_len);
+               unsigned char *p = (unsigned char *) sig;
+       const unsigned char *end = sig + sig_len;
+               size_t len;
+
+               if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
+                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+       {
+               ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+               goto sig_cleanup;
+       }
+
+       if( p + len != end )
+       {
+               ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
+               goto sig_cleanup;
+       }
+
+       if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 ||
+               ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 )
+       {
+               ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+               goto sig_cleanup;
+       }
+               ret = mbedtls_mpi_write_binary(&r, buf, 32);
+               if( ret ) {
+                       goto sig_cleanup;
+               }
+               mp_obj_t map_rkey = mp_obj_new_bytes(buf, 32);
+               ret = mbedtls_mpi_write_binary(&s, buf, 32);
+               if( ret ) {
+                       goto sig_cleanup;
+               }
+               mp_obj_t map_skey = mp_obj_new_bytes(buf, 32);
+               mbedtls_mpi_free( &r );
+       mbedtls_mpi_free( &s );
+               mp_obj_t sig_r_s[2] = {map_rkey, map_skey};
+               return mp_obj_new_tuple(2, sig_r_s);;
+       }
+       if( n_args == 3 ) {
+               size_t rlen;
+       const byte *rkey = (const byte *)mp_obj_str_get_data(args[1], &rlen);
+               size_t slen;
+       const byte *skey = (const byte *)mp_obj_str_get_data(args[2], &slen);
+
+       unsigned char *p = buf + sizeof( buf );
+       size_t len = 0;
+
+               ret = mbedtls_mpi_read_binary(&r, rkey, rlen);
+               if( ret ) {
+                       goto sig_cleanup;
+               }
+               ret = mbedtls_mpi_read_binary(&s, skey, slen);
+               if( ret ) {
+                       goto sig_cleanup;
+               }
+
+               ret = mbedtls_asn1_write_mpi(&p, buf, &s);
+               if( ret < 0 ) {
+                       goto sig_cleanup;
+               }
+               len += ret;
+               ret = mbedtls_asn1_write_mpi(&p, buf, &r);
+               if( ret < 0 ) {
+                       goto sig_cleanup;
+               }
+               len += ret;
+               ret = mbedtls_asn1_write_len(&p, buf, len);
+               if( ret < 0 ) {
+                       goto sig_cleanup;
+               }
+               len += ret;
+               ret =  mbedtls_asn1_write_tag(&p, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+               if( ret < 0 ) {
+                       goto sig_cleanup;
+               }
+               len += ret;
+               mbedtls_mpi_free( &r );
+       mbedtls_mpi_free( &s );
+               return mp_obj_new_bytes(p, len);
+       }
+       return mp_const_none;
+sig_cleanup:
+       mbedtls_mpi_free( &r );
+    mbedtls_mpi_free( &s );
+       mbedtls_raise_error(ret);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(ucryptolib_ecdsa_convert_sig_obj, 2, ucryptolib_ecdsa_convert_sig);
+
+STATIC const mp_rom_map_elem_t ucryptolib_ecdsa_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ecdsas) },
+    { MP_ROM_QSTR(MP_QSTR_curves), MP_ROM_PTR(&ucryptolib_ecdsa_curves_obj) },
+    { MP_ROM_QSTR(MP_QSTR_curve_info), MP_ROM_PTR(&ucryptolib_ecdsa_curve_info_obj) },
+    { MP_ROM_QSTR(MP_QSTR_gen_key), MP_ROM_PTR(&ucryptolib_ecdsa_genkey_obj) },
+    { MP_ROM_QSTR(MP_QSTR_get_pubkey), MP_ROM_PTR(&ucryptolib_ecdsa_get_pubkey_obj) },
+    { MP_ROM_QSTR(MP_QSTR_convert_pubkey), MP_ROM_PTR(&ucryptolib_ecdsa_convert_pubkey_obj) },
+    { MP_ROM_QSTR(MP_QSTR_convert_sig), MP_ROM_PTR(&ucryptolib_ecdsa_convert_sig_obj) },
+    { MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&ucryptolib_ecdsa_key_sign_obj) },
+    { MP_ROM_QSTR(MP_QSTR_verify), MP_ROM_PTR(&ucryptolib_ecdsa_key_verify_obj) },
+       { MP_ROM_QSTR(MP_QSTR_FORMAT_PEM), MP_ROM_INT(FORMAT_PEM) },
+       { MP_ROM_QSTR(MP_QSTR_FORMAT_DER), MP_ROM_INT(FORMAT_DER) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ucryptolib_ecdsa_locals_dict, ucryptolib_ecdsa_locals_dict_table);
+
+const mp_obj_type_t ucryptolib_ecdsa_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_ecdsa,
+    .make_new = ucryptolib_ecdsa_make_new,
+    .locals_dict = (void *)&ucryptolib_ecdsa_locals_dict,
+};
+
+#endif
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modipsec.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modipsec.c
new file mode 100644 (file)
index 0000000..c266d7e
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ * and Mnemote Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016, 2017 Nick Moore @mnemote
+ * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
+ *
+ * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky
+ * And the ESP IDF example code which is Public Domain / CC0
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objlist.h"
+#include "py/runtime.h"
+
+
+#if MICROPY_QPY_MODULE_IPSEC
+
+#include "mperrno.h"
+#include "sockets.h"
+#include "helios_ipsec.h"
+#include "helios_debug.h"
+#include "helios_dev.h"
+
+#define QPY_IPSEC_LOG(msg, ...)      custom_log(ipsec, msg, ##__VA_ARGS__)
+
+extern int Helios_NV_File_Exist(const char* file_name);
+extern int Helios_NV_File_Write(const char* file_name, void* write_buf, int write_size);
+extern int Helios_NV_File_Read(const char* file_name, void* read_buf, int read_size);
+extern int Helios_NV_File_Delete(const char* file_name);
+#define IPSEC_COUNT_FILE_NAME "quecpython_ipsec.conf"
+#define IPSEC_COUNT_LIMITED    1000
+
+/* 定义ipsec_obj_t结构体 */
+typedef struct _ipsec_obj_t {
+    mp_obj_base_t base;   //定义的对象结构体要包含该成员
+} ipsec_obj_t;
+
+const mp_obj_type_t mp_ipsec_type;
+static ipsec_obj_t* ipsec_netif = NULL;
+static int check_used_count()
+{
+       int ret = 0;
+       int count = 0;
+       // 0: not exist  1: exist
+       ret = Helios_NV_File_Exist(IPSEC_COUNT_FILE_NAME);
+       if (ret == 0) {
+               count = 1;
+               Helios_NV_File_Write(IPSEC_COUNT_FILE_NAME, &count, sizeof(count));
+               return 1;
+       }
+       
+       ret = Helios_NV_File_Read(IPSEC_COUNT_FILE_NAME, &count, sizeof(count));
+       count += 1;
+       Helios_NV_File_Write(IPSEC_COUNT_FILE_NAME, &count, sizeof(count));
+       return count;
+}
+
+STATIC mp_obj_t ipsec_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) {
+       mp_arg_check_num(n_args, n_kw, 0, 1, false);   //检查参数个数
+       (void)args;
+
+       char fw_version_str[64] = {0};
+       int ret = Helios_Dev_GetFwVersion((void *)fw_version_str, sizeof(fw_version_str));
+       if(ret != 0) {
+               mp_raise_ValueError(MP_ERROR_TEXT("ERR_IPSEC_FW_IS_WRONG"));
+       }
+       
+       QPY_IPSEC_LOG("ipsec fw_version_str: %s", fw_version_str);
+       if( strstr(fw_version_str, "BETA") || strstr(fw_version_str, "TEST") ) {
+               ret = check_used_count();
+               QPY_IPSEC_LOG("common count: %d", ret);
+               if( ret >= IPSEC_COUNT_LIMITED ) {
+                       mp_raise_ValueError(MP_ERROR_TEXT("ERR_IPSEC_USED_LIMITE"));
+               }
+       }
+       
+    if (ipsec_netif == NULL) {
+        ipsec_netif = m_new_obj_with_finaliser(ipsec_obj_t);  //创建对象,分配空间
+        //memset(ipsec_netif, 0x00, sizeof(ipsec_obj_t));
+    } else {
+        mp_raise_ValueError(MP_ERROR_TEXT("ERR_IPSEC_NETIF_IS_BUSY"));
+    }
+    ipsec_obj_t* self = ipsec_netif;
+    self->base.type = &mp_ipsec_type;         //定义对象的类型
+
+    return MP_OBJ_FROM_PTR(self);                 //返回对象的指针
+}
+
+STATIC mp_obj_t qpy_ipsec_vpn(mp_obj_t self_in, mp_obj_t local_conf, mp_obj_t remote_conf) {
+    ipsec_obj_t* self = MP_OBJ_TO_PTR(self_in);
+       int ret = 0;
+       mp_map_t *map;
+       Helios_IPSEC_Param_t ipsec_conf;
+       memset(&ipsec_conf, 0x00, sizeof(Helios_IPSEC_Param_t));
+
+       map = mp_obj_dict_get_map(local_conf);
+       for (size_t i = 0; i < map->alloc; i++) {
+       if (mp_map_slot_is_filled(map, i)) {
+
+                       switch (mp_obj_str_get_qstr(map->table[i].key)) {
+                               case MP_QSTR_wan_ip:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_str) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.local.wan_ip = (char *)mp_obj_str_get_str(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_wan_ip value: %s", ipsec_conf.local.wan_ip);
+                    break;
+                               case MP_QSTR_sub_ip:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_str) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.local.sub_ip = (char *)mp_obj_str_get_str(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_sub_ip value: %s", ipsec_conf.local.sub_ip);
+                    break;
+                               case MP_QSTR_aes:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_str) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.local.aes = (char *)mp_obj_str_get_str(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_aes value: %s", ipsec_conf.local.aes);
+                    break;
+                               case MP_QSTR_sha1:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_str) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.local.sha1 = (char *)mp_obj_str_get_str(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_sha1 value: %s", ipsec_conf.local.sha1);
+                    break;
+                               case MP_QSTR_spi:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_int) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.local.spi = mp_obj_get_int_truncated(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_spi value: %0x", ipsec_conf.local.spi);
+                    break;
+                               case MP_QSTR_port:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_int) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.local.port = mp_obj_get_int(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_port value: %d", ipsec_conf.local.port);
+                    break;
+                               default:
+                    mp_raise_OSError(MP_EINVAL);
+                                       break;
+                }
+               }
+       }
+
+       map = mp_obj_dict_get_map(remote_conf);
+    for (size_t i = 0; i < map->alloc; i++) {
+       if (mp_map_slot_is_filled(map, i)) {
+                       switch (mp_obj_str_get_qstr(map->table[i].key)) {
+                               case MP_QSTR_pub_ip:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_str) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.remote.pub_ip = (char *)mp_obj_str_get_str(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_pub_ip value: %s", ipsec_conf.remote.pub_ip);
+                    break;
+                               case MP_QSTR_sub_ip:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_str) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.remote.sub_ip = (char *)mp_obj_str_get_str(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_sub_ip value: %s", ipsec_conf.remote.sub_ip);
+                    break;
+                               case MP_QSTR_aes:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_str) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.remote.aes = (char *)mp_obj_str_get_str(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_aes value: %s", ipsec_conf.remote.aes);
+                    break;
+                               case MP_QSTR_sha1:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_str) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.remote.sha1 = (char *)mp_obj_str_get_str(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_sha1 value: %s", ipsec_conf.remote.sha1);
+                    break;
+                               case MP_QSTR_spi:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_int) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.remote.spi = mp_obj_get_int_truncated(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_spi value: %0x", ipsec_conf.remote.spi);
+                    break;
+                               case MP_QSTR_port:
+                       if (mp_obj_get_type(map->table[i].value) != &mp_type_int) {
+                         mp_raise_OSError(MP_EINVAL);
+                    }
+                                       ipsec_conf.remote.port = mp_obj_get_int(map->table[i].value);
+                    QPY_IPSEC_LOG("MP_QSTR_local_port value: %d", ipsec_conf.remote.port);
+                    break;
+                               default:
+                    mp_raise_OSError(MP_EINVAL);
+                                       break;
+                }
+               }
+       }
+
+       helios_ipsec_vpn_deinit();
+
+       ret = helios_ipsec_vpn(&ipsec_conf);
+       if( ret != 0 ) {
+               mp_raise_ValueError(MP_ERROR_TEXT("ipsec init failed"));
+       }
+#if 0
+    if (kwargs->used != 0) {
+        for (size_t i = 0; i < kwargs->alloc; i++) {
+            if (mp_map_slot_is_filled(kwargs, i)) {
+                switch (mp_obj_str_get_qstr(kwargs->table[i].key)) {
+                                       case MP_QSTR_local_wan_ip: {
+                        if (mp_obj_get_type(kwargs->table[i].value) != &mp_type_bool) {
+                            return MP_OBJ_NEW_SMALL_INT(HELIOS_WLAN_ERROR_PARAM_INVALID);
+                        }
+                        config.enable = mp_obj_is_true(kwargs->table[i].value);
+                        break;
+                    }
+                    case MP_QSTR_local_sub_ip: {
+                        if (mp_obj_get_int(kwargs->table[i].value) < HELIOS_WLAN_NETCFG_TYPE_SMARTCONFIG || mp_obj_get_int(kwargs->table[i].value) >= HELIOS_WLAN_NETCFG_TYPE_MAX) {
+                            return MP_OBJ_NEW_SMALL_INT(HELIOS_WLAN_ERROR_PARAM_INVALID);
+                        }
+                        config.type = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                    case MP_QSTR_peer_pub_ip: {
+                        config.timeout = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                    case MP_QSTR_peer_sub_ip: {
+                        if (mp_obj_get_type(kwargs->table[i].value) != &mp_type_bool) {
+                            return MP_OBJ_NEW_SMALL_INT(HELIOS_WLAN_ERROR_PARAM_INVALID);
+                        }
+                        config.enable = mp_obj_is_true(kwargs->table[i].value);
+                        break;
+                    }
+                    case MP_QSTR_aes: {
+                        if (mp_obj_get_int(kwargs->table[i].value) < HELIOS_WLAN_NETCFG_TYPE_SMARTCONFIG || mp_obj_get_int(kwargs->table[i].value) >= HELIOS_WLAN_NETCFG_TYPE_MAX) {
+                            return MP_OBJ_NEW_SMALL_INT(HELIOS_WLAN_ERROR_PARAM_INVALID);
+                        }
+                        config.type = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                    case MP_QSTR_sha1: {
+                        config.timeout = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                                       case MP_QSTR_in_seq: {
+                        config.timeout = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                    case MP_QSTR_src_port: {
+                        if (mp_obj_get_type(kwargs->table[i].value) != &mp_type_bool) {
+                            return MP_OBJ_NEW_SMALL_INT(HELIOS_WLAN_ERROR_PARAM_INVALID);
+                        }
+                        config.enable = mp_obj_is_true(kwargs->table[i].value);
+                        break;
+                    }
+                    case MP_QSTR_dst_port: {
+                        if (mp_obj_get_int(kwargs->table[i].value) < HELIOS_WLAN_NETCFG_TYPE_SMARTCONFIG || mp_obj_get_int(kwargs->table[i].value) >= HELIOS_WLAN_NETCFG_TYPE_MAX) {
+                            return MP_OBJ_NEW_SMALL_INT(HELIOS_WLAN_ERROR_PARAM_INVALID);
+                        }
+                        config.type = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                    case MP_QSTR_sha1: {
+                        config.timeout = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+                    default:
+                        return MP_OBJ_NEW_SMALL_INT(HELIOS_WLAN_ERROR_PARAM_INVALID);
+                }
+            }
+        }
+    }
+#endif
+    return MP_OBJ_NEW_SMALL_INT(ret);
+}
+//STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ipsec_vpn_obj, 1, network_ipsec_vpn);
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_ipsec_vpn_obj, qpy_ipsec_vpn);
+
+
+/*=============================================================================*/
+/* FUNCTION: qpy_module_ipsec_deinit                                         */
+/*=============================================================================*/
+/*!@brief: deinit ipsec module
+ *
+ *
+ * @return:
+ *     0       -       success
+ */
+ /*=============================================================================*/
+STATIC mp_obj_t qpy_module_ipsec_delete(mp_obj_t self_in) {
+    ipsec_obj_t* self = MP_OBJ_TO_PTR(self_in);
+       helios_ipsec_vpn_deinit();
+    ipsec_netif = NULL;
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_module_ipsec_delete_obj, qpy_module_ipsec_delete);
+
+
+STATIC const mp_rom_map_elem_t ipsec_netif_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR___name__),MP_ROM_QSTR(MP_QSTR_ipsec) },
+    { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&qpy_module_ipsec_delete_obj) },
+    { MP_ROM_QSTR(MP_QSTR_vpn), MP_ROM_PTR(&qpy_ipsec_vpn_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(ipsec_locals_dict, ipsec_netif_locals_dict_table);
+
+const mp_obj_type_t mp_ipsec_type = {
+    .base = { &mp_type_type },
+    .name = MP_QSTR_ipsec,
+    .make_new = ipsec_make_new,
+    .locals_dict = (mp_obj_dict_t*)&ipsec_locals_dict,
+};
+
+#endif // MICROPY_PY_NETWORK_WLAN
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modjrtc_test.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modjrtc_test.c
new file mode 100644 (file)
index 0000000..2f14f4f
--- /dev/null
@@ -0,0 +1,291 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include "obj.h"
+#include "runtime.h"
+
+
+#define HELIOS_JRTC_LOG(msg, ...)      custom_log("JRTC", msg, ##__VA_ARGS__)
+/** 通话错误值 */
+enum jrtc_error
+{
+    JRTC_ENIL   = 0,  /* unknown error */
+    JRTC_EPERM  = 1,  /* Operation not permitted */
+    JRTC_ENONET = 64, /* Machine is not on the network */
+    JRTC_EPROTO = 71, /* Protocol error */
+    JRTC_EMSGSIZE = 90,  /* Message too long */
+    JRTC_ECONNRESET=104, /* Connection reset by peer */
+    JRTC_ETIMEDOUT =101, /* Connection timed out */
+    JRTC_ECONNREFUSED=111,/* Connection refused or closed */
+    JRTC_EDECLINE = 129, /* Peer decline the call */
+    JRTC_EINVOKETIMEOUT = 130, /* IoTUnit invoke timeout */
+    JRTC_ECALLSERVERERROR = 131, /* Call server error */
+    JRTC_EROOMNOTFND = 132, /* Room or callee not found */
+    JRTC_ECALLTIMEOUT = 133, /* Call timeout */
+    JRTC_ENOTREG = 134, /* device id not registered */
+    JRTC_ELOGIN = 135, /* device id login failed */
+    JRTC_EAUDIOCALL = 252, /* external audio call, don't close audio deivce */
+    JRTC_EAUDIO=253,  /* Audio device error */
+    JRTC_EVIDEO=254,  /* Video device error */
+    JRTC_EBYE = 255,  /* Success, Closed by peer leave */
+};
+
+struct jrtc_t
+{
+    void* task; //必须放在头部
+    struct jrtc_t *next;
+    volatile unsigned char state, error;
+    char room[65], uid[65], vid[65], screen[65];
+    unsigned short srvIdx, gop, istats;//统计周期,默认5s
+    unsigned short video_cs_threshold;//卡顿阀值,默认300毫秒
+    unsigned short auto_req_slen;
+    struct AES_ctx *aes_ctx;
+    struct net_sock *tcpfd, *udpfd;
+    struct net_addr *udp_addr, *srv_addr;
+    unsigned char *recv_buf, *ared_buf, *vfec_buf;
+    unsigned short recv_off, ared_off;
+    unsigned hash, vfec_size, role, status;
+    struct jrtc_image_t *camera, *video;
+    unsigned audio_ssrc, video_ssrc;//local ssrc
+    unsigned char udp_fail_count;
+    char audio_pt, ared_pt;
+    char video_pt, vfec_pt;
+    unsigned short audio_seqno, video_seqno, vfec_seqno;
+    unsigned char audio_ptime;
+    unsigned char req_cam:2;
+    unsigned char req_batch:2;
+    unsigned char req_event:3;//1:status,2:role,3:video,4:index
+    unsigned char audio_received:1;
+    unsigned char video_started:1, audio_started:1, leave_called:1, video_changed:1;
+    unsigned char aenc_idx:2, adec_idx:2, venc_idx:2, vdec_idx:2;
+    char netst_pt, volu_pt;
+    signed char index;
+    unsigned char video_index;
+    unsigned char recv_types;//RECV_TYPE
+    unsigned recv_ms, send_ms, stats_ms, last_ms;
+    struct rtp_lostr_t* audio_lostR, *video_lostR;
+    struct rtp_stats_t* audio_stats, *video_stats;
+    unsigned recv_frame_count, recv_frame_ms;//fps
+    unsigned video_cs;//统计周期内(istats)卡顿毫秒数和
+    void (*effect_cb)(struct jrtc_photo_t* frame);
+    //发送请求处理
+    void* req_sem;
+    char req_id[65];
+    unsigned req_mask, req_value;
+};
+
+typedef struct{
+    uint32_t int_type;
+    uint32_t port;
+    uint32_t read_lenth;
+    c_callback_t callback;
+}st_CallBack_jrtc;
+
+struct jrtc_image_t
+{
+    void* data;
+    unsigned short width, height, kbps;
+    char fps;
+    char format;/*< 0: I420; 1: NV12 */
+    volatile char put, get;
+};
+static struct jrtc_image_t send = {0};
+static struct jrtc_image_t recieve = {0};
+
+static struct jrtc_t* test;
+
+/* 定义jrtc_obj_t结构体 */
+typedef struct _jrtc_obj_t
+{
+    mp_obj_base_t base;   //定义的对象结构体要包含该成员
+}jrtc_obj_t;
+
+const mp_obj_type_t jrtc_type;
+
+/** 当前的版本号 */
+#define JRTC_VERTION   "1.4.0"
+
+static Helios_MsgQ_t int_happen_q = 0;
+static Helios_Thread_t int_handle_task_id = 0;
+
+static c_callback_t *usr_callback[5] = {NULL};
+static c_callback_t cb[5] = {0};
+
+mp_buffer_info_t roomid, ticket;
+
+void jrtc_handle(void * argv) {
+    uint8_t open_state = 0;
+    int ret = -1
+    while (1) {
+        ret = Helios_MsgQ_Get(int_happen_q, (void *)&open_state, sizeof(uint8_t), HELIOS_WAIT_FOREVER);
+               if (ret != 0)
+               {
+                       HELIOS_JRTC_LOG("interrupt handle thread failed to get queue\n");
+                       continue;
+               }
+        if (open_state == 1) {
+            if (jrtc_state(test) == JRTC_CLOSED) {
+                test = jrtc_open(roomid.buf, ticket.buf, &recieve, &send);
+                jrtc_activate(test, JRTC_AUDIO|JRTC_CAMERA);
+            }
+        }
+        else if (open_state == 0) {
+            if (jrtc_state(test) != JRTC_CLOSED) {
+                jrtc_close(test, JRTC_ENIL);
+            }
+        }
+    }
+}
+
+STATIC mp_obj_t mp_jrtc_init(void) {
+    Helios_ThreadAttr attr = {0};
+       if (int_happen_q == 0) {
+               int_happen_q = Helios_MsgQ_Create(1, sizeof(uint8_t));
+       }
+       if(int_handle_task_id == 0)
+       {
+           attr.name = "jrtc_handle";
+        attr.stack_size = 1024*4;
+        attr.priority = 90;
+        attr.entry = jrtc_handle;
+
+        int_handle_task_id = Helios_Thread_Create(&attr);
+        if (0 == int_handle_task_id)
+        {
+            mp_raise_ValueError("create interrupt handle task failed\n");
+        }
+       }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_jrtc_init_obj, mp_jrtc_init);
+
+STATIC mp_obj_t mp_jrtc_config (size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+    int ret = 0;
+    enum { ARG_appkey, ARG_uid, ARG_srvURL,  ARG_key};
+    static const mp_arg_t allowed_args[] = 
+    {
+       { MP_QSTR_appkey,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_uid,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_srvURL,      MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_key,      MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+    };
+    mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
+    mp_buffer_info_t appkey, uid, srvURL, ;
+    mp_get_buffer_raise(args[ARG_appkey].u_obj, &appkey, MP_BUFFER_READ);
+    mp_get_buffer_raise(args[ARG_uid].u_obj, &uid, MP_BUFFER_READ);
+    mp_get_buffer_raise(args[ARG_srvURL].u_obj, &srvURL, MP_BUFFER_READ);
+
+    uint8_t key = args[ARG_key].u_int;
+
+    ret = jrtc_config(appkey.buf, uid.buf, srvURL.buf, key);
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t mp_jrtc_open (size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+    int ret = 0;
+    enum { ARG_roomid, ARG_ticket, ARG_recieve, ARG_send};
+    static const mp_arg_t allowed_args[] = 
+    {
+       { MP_QSTR_roomid,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_ticket,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_recieve,      MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_send,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+    };
+    mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
+    //mp_buffer_info_t roomid, ticket;
+    mp_get_buffer_raise(args[ARG_roomid].u_obj, &roomid, MP_BUFFER_READ);
+    mp_get_buffer_raise(args[ARG_ticket].u_obj, &ticket, MP_BUFFER_READ);
+    size_t len;
+    mp_obj_t *elem;
+    mp_obj_get_array(args[ARG_send].u_obj, &len, &elem);
+    recieve.fps = mp_obj_get_int(elem[0]);
+    recieve.kbps = mp_obj_get_int(elem[1]);
+    recieve.width = mp_obj_get_int(elem[2]);
+    recieve.height= mp_obj_get_int(elem[3]);
+    mp_obj_get_array(args[ARG_recieve].u_obj, &len, &elem);
+    send.fps = mp_obj_get_int(elem[4]);
+    send.kbps = mp_obj_get_int(elem[5]);
+    send.width = mp_obj_get_int(elem[6]);
+    send.height = mp_obj_get_int(elem[7]);
+
+    uint8_t int_happen = 1;
+    Helios_MsgQ_Put(int_happen_q, (const void *)&int_happen, sizeof(uint8_t), HELIOS_NO_WAIT);
+    
+    return mp_obj_new_int(1);
+}
+
+STATIC mp_obj_t set_callback(mp_obj_t self_in, mp_obj_t port_obj, const mp_obj_t handler)
+{
+       int port = mp_obj_get_int(port_obj);
+       jrtc_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+    usr_callback[port] = &cb[port];
+    mp_sched_schedule_callback_register(usr_callback[port], handler);
+
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(set_callback_obj, set_callback);
+
+STATIC mp_obj_t mp_jrtc_close (size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+    int ret = 0;
+    enum { ARG_jc, ARG_err };
+    static const mp_arg_t allowed_args[] = 
+    {
+       { MP_QSTR_jc,      MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_err,     MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+    };
+    mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
+
+    uint16_t device = args[ARG_err].u_int;
+    ret = jrtc_close (jc, ARG_err);
+    return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t mp_jrtc_activate (size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+    int ret = 0;
+    enum { ARG_jc, ARG_device };
+    static const mp_arg_t allowed_args[] = 
+    {
+       { MP_QSTR_jc,      MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_device,  MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+    };
+    mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
+    
+    uint16_t device = args[ARG_device].u_int;
+
+    ret = jrtc_activate (jc, devices);
+    return mp_obj_new_int(ret);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mp_jrtc_config_obj, mp_jrtc_config);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mp_jrtc_open_obj, mp_jrtc_open);
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(mp_jrtc_close_obj, mp_jrtc_close);
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(mp_jrtc_activate_obj, mp_jrtc_activate);
+
+/* 定义的modjrtc本地字典 */
+STATIC const mp_rom_map_elem_t jrtc_locals_dict_table[] = {
+    {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_jrtc)},   //这个对应python层面的__name__ 属性
+    {MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&mp_jrtc_config_obj)}, //新增的modtest_obj_func_withargs对象注册到modtest中
+    {MP_ROM_QSTR(MP_QSTR_set_callback), MP_ROM_PTR(&set_callback_obj) },
+    {MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_jrtc_open_obj)}, 
+    {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_jrtc_close_obj)},
+    {MP_ROM_QSTR(MP_QSTR_activate), MP_ROM_PTR(&mp_jrtc_activate_obj)},
+};
+
+/* 把modjrtc_globals_table注册到 mp_module_modjrtc_globals里面去 */
+STATIC MP_DEFINE_CONST_DICT(jrtc_locals_dict, jrtc_locals_dict_table);   
+
+/* 定义mp_obj_type_t类型的结构体;注意这里和定义module使用的类型是不一样的 */
+const mp_obj_type_t jrtc_type = {
+    .base={ &mp_type_type }, 
+    .name = MP_QSTR_jrtc, //type类的name属性是放在这里定义,而不是放在DICT中
+    //.make_new = can_mcp2515_make_new, //添加的make new属性
+    .locals_dict = (mp_obj_dict_t*)&jrtc_locals_dict, //注册jrtc_locals_dict
+};
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modlvgl_other_hander.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modlvgl_other_hander.c
new file mode 100644 (file)
index 0000000..6a98f99
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(CONFIG_LVGL)
+
+
+#include "modlvgl_other_hander.h"
+
+#include "helios_debug.h"
+#include "helios_flash.h"
+
+
+#define QPY_LVGL_LOG(msg, ...)      //custom_log(lvgl, msg, ##__VA_ARGS__)
+
+
+static img_info_list* hash_list = NULL;
+static uint16_t img_count = 0;
+static uint32_t img_flash_start_addr = 0;
+static bool have_customer_img = false;
+
+
+
+static int32_t get_per_hash( char * src )
+{    
+    /*----------------------------------------------------------------*/
+    /* Local Variables                                                */
+    /*----------------------------------------------------------------*/
+    uint32_t         h, v;
+    char *    p; 
+
+    /*----------------------------------------------------------------*/
+    /* Code Body                                                      */
+    /*----------------------------------------------------------------*/
+    for(h=0, p = (char *)src; *p ; p++)
+    {
+        h = 5527 * h + 7 *(*p);
+        v = h & 0x0000ffff;
+        h ^= v*v;
+    }
+
+    return h;
+}
+
+
+static int32_t create_api_hash(char* api)
+{
+    int32_t hash,i;
+
+    hash = get_per_hash(api);
+
+    for (i=0;i<img_count;i++)
+    {
+        if (hash == hash_list[i].hash)
+            return -1;
+    }
+
+    return hash;
+}
+
+static int32_t MatchInList(int32_t hash, img_info_list* hashlist, int32_t list_max )
+{
+    int32_t iMax = list_max - 1, iMin = 0;
+
+
+    if( hash<hashlist[iMin].hash|| hash>hashlist[iMax].hash)
+        return -1;
+    
+    do{
+        if( hash > hashlist[iMin+(iMax-iMin)/2].hash)
+            iMin = iMin+(iMax-iMin)/2;
+        else
+            iMax = iMin+(iMax-iMin)/2;
+
+    }while( (iMax-iMin)>1 );
+
+    if( hash == hashlist[iMax].hash)
+    {
+        return iMax;
+    }
+    else if( hash == hashlist[iMin].hash)
+    {
+        return iMin;
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int32_t helios_lv_get_img_addr_prt(char* func_name )
+{
+    int32_t        resid = -1;
+    int32_t        hashvalue = 0;
+
+    if( func_name == NULL )
+    {
+        return 0;
+    }
+    {
+        hashvalue = get_per_hash( func_name );
+        resid = MatchInList( hashvalue, hash_list, img_count);
+
+    }
+    if( (resid >= 0) && (resid < img_count) )
+        return (int32_t)hash_list[resid].img_ptr;
+    else
+        return 0;
+}
+
+static void ApiTableSplitArray(img_info_list* arr, int32_t low, int32_t high, int32_t *p ) 
+{ 
+    int32_t i, j;
+    int32_t item;
+    img_info_list t;
+
+    item = arr[low].hash;
+    i = low;
+    j = high;
+
+    while( i < j )
+    {
+        /*  move from R to L in search of element < item */
+        while ( arr[j].hash> item )
+            j = j - 1;
+
+        /*  move from L to R in search of element > item */
+        while ( arr[i].hash<= item  &&  i < j )
+            i = i + 1;
+
+        if ( i < j )
+        {
+            t = arr[i];
+            arr[i] = arr[j];
+            arr[j] = t;
+        }
+    }
+    *p = j;
+    t = arr[low];
+    arr[low] = arr[*p];
+    arr[*p] = t;
+}
+
+static void ApiTableQuickSort(img_info_list* arr, int32_t low, int32_t high )
+{
+    int32_t pos;
+
+    if( low < high )
+    {
+        ApiTableSplitArray( arr, low, high, &pos );
+        ApiTableQuickSort( arr, low, pos - 1 );
+        ApiTableQuickSort( arr, pos + 1, high );
+    }
+}
+
+
+
+void helios_lv_customer_img_handle(void)
+{
+       int i = 0;
+       HeliosFlashPartiCtx *usr_t = Helios_Flash_GetPartiCtx("customer_image");
+       if(usr_t) {
+               QPY_LVGL_LOG("name[%s], addr[%x], size[%d]\n", usr_t->name, usr_t->addr, usr_t->size);
+               
+
+               // check header
+               char identity_buff[5] = {0};
+               memcpy(&identity_buff, (char*)usr_t->addr, 5);
+               if(0 != strncmp(identity_buff, "start", 5)) {
+                       QPY_LVGL_LOG("Start identity matching failed\r\n");
+                       return;
+               }
+
+               memcpy(&img_count, (char*)usr_t->addr + 5, 2);
+               QPY_LVGL_LOG("img_count[%d]\n",img_count);
+
+               customer_img_st *img_info = (customer_img_st*)(usr_t->addr + 7);
+
+               hash_list = calloc(img_count, sizeof(img_info_list));
+               if(img_info == NULL) 
+               {
+                       QPY_LVGL_LOG("hash_list calloc[%d] fail\n", img_count * sizeof(img_info_list));
+                       if(img_info) {
+                               free(img_info);
+                               img_info = NULL;
+                       }
+                       return;
+               }
+
+               
+               for(i = 0; i < img_count; i++)
+               {
+                       hash_list[i].hash = get_per_hash(img_info[i].name);
+//                     hash_list[i].img_ptr = usr_t->addr + img_info[i].start_addr;
+                       hash_list[i].img_ptr = usr_t->addr + 7 + sizeof(customer_img_st)*i;
+                       QPY_LVGL_LOG("img[%d], name[%s], offset[%d], len[%d] hash[%x], img_prt[%x]\n", i, img_info[i].name, img_info[i].start_addr, img_info[i].len, hash_list[i].hash, hash_list[i].img_ptr);
+               }
+               
+               
+               ApiTableQuickSort(hash_list, 0, img_count -1);  
+
+
+               for(i = 0; i < img_count; i++)
+               {
+                       QPY_LVGL_LOG("name[%s],addr[%x]\n", img_info[i].name, helios_lv_get_img_addr_prt(img_info[i].name));
+               }
+
+               have_customer_img = true;
+               img_flash_start_addr = usr_t->addr;
+               
+       } 
+       
+}
+
+
+bool helios_lv_get_img_dsc_by_img_name(const void* src, lv_img_dsc_t* img_src) 
+{
+       memset(img_src, 0, sizeof(lv_img_dsc_t));
+       if(have_customer_img == true && 0 == strncmp(src, "img:", 4)) 
+       {
+               customer_img_st* img_info = (customer_img_st*)helios_lv_get_img_addr_prt((char*)src);
+               if(img_info) 
+               {
+                       img_src->data = img_flash_start_addr + img_info->start_addr;
+                       img_src->data_size = img_info->len;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+#endif
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modlvgl_other_hander.h b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modlvgl_other_hander.h
new file mode 100644 (file)
index 0000000..19e81bf
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(CONFIG_LVGL)
+
+
+#ifndef __MODLVGL_OTHER_HANDER_H__
+#define __MODLVGL_OTHER_HANDER_H__
+
+ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "lvgl.h"
+
+
+
+typedef struct 
+{
+       char name[32];
+       uint32_t start_addr;
+       uint32_t len;
+} customer_img_st;
+
+typedef struct
+{
+    int32_t hash;
+    uint32_t img_ptr;
+} img_info_list;
+
+
+
+void helios_lv_customer_img_handle(void);
+
+bool helios_lv_get_img_dsc_by_img_name(const void* src, lv_img_dsc_t* img_src);
+
+
+
+#endif
+
+#endif
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modnfc.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modnfc.c
new file mode 100644 (file)
index 0000000..0a5ef55
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ ******************************************************************************
+ * @file    modnfc.c
+ * @author  felix
+ * @version V1.0.0
+ * @date    2024/02/19
+ * @brief   xxx
+ ******************************************************************************
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include "mpconfigport.h"
+
+#include "compile.h"
+#include "runtime.h"
+
+#if MICROPY_QPY_MODULE_NFC
+
+extern const mp_obj_type_t NFC_SL6320_type;
+
+
+STATIC const mp_rom_map_elem_t nfc_module_globals_table[] = {
+       { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_nfc) },
+#if MICROPY_QPY_NFC_SL6320
+       { MP_ROM_QSTR(MP_QSTR_SL6320), MP_ROM_PTR(&NFC_SL6320_type) },
+#endif
+
+
+};
+
+STATIC MP_DEFINE_CONST_DICT(nfc_module_globals, nfc_module_globals_table);
+
+const mp_obj_module_t mp_module_nfc = {
+       .base = { &mp_type_module },
+       .globals = (mp_obj_dict_t *)&nfc_module_globals,
+};
+
+
+#endif
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modsftp.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modsftp.c
new file mode 100644 (file)
index 0000000..9ef2042
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mpconfigport.h"
+
+#if MICROPY_QPY_MODULE_SFTP || MICROPY_QPY_MODULE_SSH
+#include "helios_fs.h"
+#include "extmod/vfs.h"
+#include "runtime.h"
+
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+
+#include "helios_debug.h"
+#define QPY_SFTP_LOG(msg, ...)      custom_log(SFTP, msg, ##__VA_ARGS__)
+
+typedef struct _sftp_obj_t {
+    mp_obj_base_t base;
+    int sock_id;
+    LIBSSH2_SESSION *session;
+    LIBSSH2_CHANNEL *channel;
+} sftp_obj_t;
+
+const mp_obj_type_t sftp_type;
+const mp_obj_type_t ssh_type;
+extern int socket_obj_t_get_fd(mp_obj_t sock);
+
+STATIC void sftp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+    sftp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    //mp_printf(print, "sock_id = %u, ",self->sock_id);
+}
+
+STATIC mp_obj_t sftp_handshake(mp_obj_t self_in, mp_obj_t sock_in)
+{
+    sftp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_obj_t sock = sock_in;
+    int rc = 0;
+    
+    self->sock_id = socket_obj_t_get_fd(sock);
+
+    //libssh2_trace_sethandler(self->session, NULL, libssh2_print);
+    //libssh2_trace(self->session, ~0);
+
+    while((rc = libssh2_session_handshake(self->session, self->sock_id)) == LIBSSH2_ERROR_EAGAIN);
+
+    if (rc) 
+    {
+        libssh2_session_disconnect(self->session, "Normal Shutdown");
+        libssh2_session_free(self->session);
+        QPY_SFTP_LOG("Failure establishing SSH session: %d\n", rc);
+        mp_raise_ValueError(MP_ERROR_TEXT("libssh2 session handshake failed\r\n"));
+    }
+
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(sftp_handshake_obj, sftp_handshake);
+
+STATIC mp_obj_t sftp_agent_auth(mp_obj_t self_in, mp_obj_t username_in, mp_obj_t password_in)
+{
+    sftp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    const char *username_str = mp_obj_str_get_str(username_in);
+    const char *password_str = mp_obj_str_get_str(password_in);
+
+    const char *fingerprint;
+    fingerprint = libssh2_hostkey_hash(self->session, LIBSSH2_HOSTKEY_HASH_SHA1);
+
+    QPY_SFTP_LOG("Fingerprint: ");
+    for(int i = 0; i < 20; i++) {
+        QPY_SFTP_LOG("%02X ", (unsigned char)fingerprint[i]);
+    }
+    QPY_SFTP_LOG("\n");
+
+    if(libssh2_userauth_password(self->session, username_str, password_str)) {
+        mp_raise_ValueError(MP_ERROR_TEXT("\tAuthentication by password failed!\n"));
+    }
+    else {
+        QPY_SFTP_LOG("\tAuthentication by password succeeded.\n");
+    }
+
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(sftp_agent_auth_obj, sftp_agent_auth);
+
+#if MICROPY_QPY_MODULE_SFTP
+STATIC mp_obj_t sftp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) 
+{
+    sftp_obj_t *self = m_new_obj_with_finaliser(sftp_obj_t);
+
+    self->base.type = &sftp_type;
+
+    int rc = libssh2_init(0);
+    if(rc != 0) {
+        QPY_SFTP_LOG("libssh2 initialization failed (%d)\n", rc);
+        mp_raise_ValueError(MP_ERROR_TEXT("libssh2 initialization failed\r\n"));
+    }
+
+    self->session = libssh2_session_init();
+    if (!self->session) {
+        QPY_SFTP_LOG("libssh2_session_init() failed\n");
+        mp_raise_ValueError(MP_ERROR_TEXT("libssh2 session init failed\r\n"));
+    }
+
+    return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t sftp_read_file(mp_obj_t self_in, mp_obj_t path_in)
+{
+    sftp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    const char *path_str = mp_obj_str_get_str(path_in);
+
+    LIBSSH2_SFTP *sftp_session = NULL;
+    LIBSSH2_SFTP_HANDLE *sftp_file = NULL;
+    unsigned long file_size = 0;
+    int nread_num = 0;
+
+    // 初始化SFTP会话
+    sftp_session = libssh2_sftp_init(self->session);
+
+    if (!sftp_session) {
+        mp_raise_ValueError(MP_ERROR_TEXT("\t sftp failed.\n"));
+    }
+
+    // 打开远程文件
+    sftp_file = libssh2_sftp_open(sftp_session, path_str, LIBSSH2_FXF_READ, 0);
+
+    if (!sftp_file) {
+        libssh2_sftp_shutdown(sftp_session);
+        QPY_SFTP_LOG("open file error: %d\n", libssh2_sftp_last_error(sftp_session));
+        mp_raise_ValueError(MP_ERROR_TEXT("\t open file error.\n"));
+    }
+
+    // 获取文件大小
+    LIBSSH2_SFTP_ATTRIBUTES file_stats;
+    if (libssh2_sftp_stat(sftp_session, path_str, &file_stats)) {
+        libssh2_sftp_close(sftp_file);
+        libssh2_sftp_shutdown(sftp_session);
+        QPY_SFTP_LOG("get file size error: %d\n", libssh2_sftp_last_error(sftp_session));
+        mp_raise_ValueError(MP_ERROR_TEXT("\t get file size error.\n"));
+    }
+
+    file_size = file_stats.filesize;
+
+    vstr_t vstr;
+    vstr_init_len(&vstr, file_size);
+    vstr.len = file_size;
+
+    int nread = libssh2_sftp_read(sftp_file, (char *)vstr.buf, file_size);
+    if (nread < 0){
+        libssh2_sftp_close(sftp_file);
+        libssh2_sftp_shutdown(sftp_session);
+        QPY_SFTP_LOG("read file error: %d\n", libssh2_sftp_last_error(sftp_session));
+        mp_raise_ValueError(MP_ERROR_TEXT("\t read file error.\n"));
+    }
+
+    libssh2_sftp_close(sftp_file);
+    libssh2_sftp_shutdown(sftp_session);
+
+    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(sftp_read_file_obj, sftp_read_file);
+
+STATIC mp_obj_t sftp_write_file (size_t n_args, const mp_obj_t *args)
+{
+    sftp_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    const char *path_str = mp_obj_str_get_str(args[3]);
+
+    const int method = mp_obj_get_int(args[2]);
+
+    int size = 0, n = 0, nwritten = 0;
+    mp_buffer_info_t fileinfo;
+    unsigned char* filedata = NULL;
+
+    if (method == 0)
+    {
+        HeliosFILE *fpub = NULL;
+        const char *file_name = mp_obj_str_get_str(args[1]);
+
+        if (strlen(file_name) > 256)//max file name size
+        {
+            mp_raise_ValueError(MP_ERROR_TEXT("File path too long"));
+        }
+
+        char path[256];
+        memset(path, 0, sizeof(path));
+        sprintf(path, "U:/%s", file_name);
+        if( ( fpub = Helios_fopen( path, "rb" ) ) == NULL )
+        {
+            Helios_fclose( fpub );
+            mp_raise_ValueError(MP_ERROR_TEXT("{RSA} failed encrypt Helios_fopen"));
+        }
+
+        Helios_fseek(fpub, 0, SEEK_END);
+        if ((size = Helios_ftell(fpub)) == -1)
+        {
+            Helios_fclose( fpub );
+            mp_raise_ValueError(MP_ERROR_TEXT("{RSA} failed encrypt Helios_ftell"));
+        }
+        Helios_fseek(fpub, 0, SEEK_SET);
+
+        n = (size_t)size;
+        if (n + 1 == 0 || (filedata = malloc(n + 1)) == NULL)
+        {
+            Helios_fclose( fpub );
+            mp_raise_ValueError(MP_ERROR_TEXT("{RSA} failed encrypt Helios_fclose"));
+        }
+
+        if (Helios_fread(filedata, 1, n, fpub) != (int) n)
+        {
+            Helios_fclose( fpub );
+            free(filedata);
+            filedata = NULL;
+            mp_raise_ValueError(MP_ERROR_TEXT("{RSA} failed encrypt fread "));
+        }
+        Helios_fclose( fpub );
+    }
+    else if (method == 1)
+    {
+        mp_get_buffer_raise(args[1], &fileinfo, MP_BUFFER_READ);
+
+        if (fileinfo.len <= 0)
+        {
+            mp_raise_ValueError(MP_ERROR_TEXT("input data FAIL"));
+        }
+    }
+
+    LIBSSH2_SFTP *sftp_session = NULL;
+    LIBSSH2_SFTP_HANDLE *sftp_file = NULL;
+    LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+    // 初始化SFTP会话
+    sftp_session = libssh2_sftp_init(self->session);
+
+    if (!sftp_session) {
+        mp_raise_ValueError(MP_ERROR_TEXT("\t sftp failed.\n"));
+    }
+
+    // 打开远程文件
+    /* Request a file via SFTP */
+    sftp_file = libssh2_sftp_open(sftp_session, path_str, LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC,
+                                    LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH);
+
+    if (!sftp_file) {
+        libssh2_sftp_shutdown(sftp_session);
+        QPY_SFTP_LOG("open file error: %d\n", libssh2_sftp_last_error(sftp_session));
+        mp_raise_ValueError(MP_ERROR_TEXT("\t open file error.\n"));
+    }
+
+    if(libssh2_sftp_fstat_ex(sftp_file, &attrs, 0) < 0) {
+        libssh2_sftp_close(sftp_file);
+        libssh2_sftp_shutdown(sftp_session);
+        QPY_SFTP_LOG("libssh2_sftp_fstat_ex error: %d\n", libssh2_sftp_last_error(sftp_session));
+        mp_raise_ValueError(MP_ERROR_TEXT("\t libssh2_sftp_fstat_ex error.\n"));
+    }
+    else {
+        libssh2_sftp_seek64(sftp_file, attrs.filesize);
+    }
+    
+    if (!sftp_file) {
+        libssh2_sftp_close(sftp_file);
+        libssh2_sftp_shutdown(sftp_session);
+        QPY_SFTP_LOG("seek file error: %d\n", libssh2_sftp_last_error(sftp_session));
+        mp_raise_ValueError(MP_ERROR_TEXT("\t seek file error.\n"));
+    }
+    
+    if (method == 0)
+    {
+        nwritten = libssh2_sftp_write(sftp_file, (const char *)filedata, size);
+
+        free(filedata);
+        filedata = NULL;
+
+        if(nwritten < 0) {
+            libssh2_sftp_close(sftp_file);
+            libssh2_sftp_shutdown(sftp_session);
+            QPY_SFTP_LOG("seek file error: %d\n", libssh2_sftp_last_error(sftp_session));
+            mp_raise_ValueError(MP_ERROR_TEXT("\t seek file error.\n"));
+        }
+    }
+    else if (method == 1)
+    {
+        nwritten = libssh2_sftp_write(sftp_file, fileinfo.buf, fileinfo.len);
+
+        if(nwritten < 0) {
+            libssh2_sftp_close(sftp_file);
+            libssh2_sftp_shutdown(sftp_session);
+            QPY_SFTP_LOG("seek file error: %d\n", libssh2_sftp_last_error(sftp_session));
+            mp_raise_ValueError(MP_ERROR_TEXT("\t seek file error.\n"));
+        }
+    }
+
+    libssh2_sftp_close(sftp_file);
+    libssh2_sftp_shutdown(sftp_session);
+
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sftp_write_file_obj, 4, 4, sftp_write_file);
+
+STATIC mp_obj_t sftp_deinit(mp_obj_t self_in)
+{
+    sftp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    if (self->session) 
+    {
+        libssh2_session_disconnect(self->session, "Normal Shutdown");
+        libssh2_session_free(self->session);
+        self->session = NULL;
+    }
+
+    libssh2_exit();
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(sftp_deinit_obj, sftp_deinit);
+
+STATIC const mp_rom_map_elem_t sftp_locals_dict_table[] = 
+{
+    //{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&sftp_init_obj) },
+    { MP_ROM_QSTR(MP_QSTR_handshake), MP_ROM_PTR(&sftp_handshake_obj) },
+    { MP_ROM_QSTR(MP_QSTR_agent_auth), MP_ROM_PTR(&sftp_agent_auth_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&sftp_read_file_obj) },
+    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&sftp_write_file_obj) },
+    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sftp_deinit_obj) },
+
+};
+STATIC MP_DEFINE_CONST_DICT(sftp_locals_dict, sftp_locals_dict_table);
+
+const mp_obj_type_t sftp_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_usftp,
+    .print = sftp_print,
+    .make_new = sftp_make_new,
+    .locals_dict = (mp_obj_dict_t *)&sftp_locals_dict,
+};
+
+STATIC const mp_rom_map_elem_t mp_module_sftp_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usftp) },
+    { MP_ROM_QSTR(MP_QSTR_sftp), MP_ROM_PTR(&sftp_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_sftp_globals, mp_module_sftp_globals_table);
+
+const mp_obj_module_t mp_module_usftp = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&mp_module_sftp_globals,
+};
+#endif //MICROPY_QPY_MODULE_SFTP 
+
+#if MICROPY_QPY_MODULE_SSH
+/////////////// SSH ///////////////
+STATIC mp_obj_t ssh_execute(mp_obj_t self_in, mp_obj_t exec_in)
+{
+    sftp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+    if (!self->session)
+    {
+        mp_raise_ValueError(MP_ERROR_TEXT("exec failed\r\n"));
+    }
+
+    self->channel = libssh2_channel_open_session(self->session);
+    if (!self->channel) {
+        QPY_SFTP_LOG("libssh2_channel_open_session() failed\n");
+        mp_raise_ValueError(MP_ERROR_TEXT("libssh2 channel open failed\r\n"));
+    }
+
+    const char *exec_str = mp_obj_str_get_str(exec_in);
+
+    if(libssh2_channel_exec(self->channel, exec_str))
+    {
+        QPY_SFTP_LOG("sftp_execute() failed\n");
+        mp_raise_ValueError(MP_ERROR_TEXT("sftp execute failed\r\n"));
+    }
+
+    return mp_obj_new_int(1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssh_execute_obj, ssh_execute);
+
+STATIC mp_obj_t ssh_channel_read(mp_obj_t self_in)
+{
+    sftp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+    if (!self->session || !self->channel)
+    {
+        mp_raise_ValueError(MP_ERROR_TEXT("channel session failed\r\n"));
+    }
+
+    char buf[1024];
+
+    ssize_t err = libssh2_channel_read(self->channel, buf, sizeof(buf) - 1);
+    if(err < 0)
+    {
+        mp_raise_ValueError(MP_ERROR_TEXT("channel read failed\r\n"));
+    }
+
+    libssh2_channel_free(self->channel);
+
+    vstr_t vstr;
+    vstr_init_len(&vstr, err);
+    memcpy(vstr.buf, &buf, err);
+
+    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(ssh_channel_read_obj, ssh_channel_read);
+
+
+STATIC mp_obj_t ssh_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) 
+{
+    sftp_obj_t *self = m_new_obj_with_finaliser(sftp_obj_t);
+
+    self->base.type = &ssh_type;
+
+    int rc = libssh2_init(0);
+    if(rc != 0) {
+        QPY_SFTP_LOG("libssh2 initialization failed (%d)\n", rc);
+        mp_raise_ValueError(MP_ERROR_TEXT("libssh2 initialization failed\r\n"));
+    }
+
+    self->session = libssh2_session_init();
+    if (!self->session) {
+        QPY_SFTP_LOG("libssh2_session_init() failed\n");
+        mp_raise_ValueError(MP_ERROR_TEXT("libssh2 session init failed\r\n"));
+    }
+
+    return MP_OBJ_FROM_PTR(self);
+}
+
+
+STATIC const mp_rom_map_elem_t ssh_locals_dict_table[] = 
+{
+    { MP_ROM_QSTR(MP_QSTR_handshake), MP_ROM_PTR(&sftp_handshake_obj) },
+    { MP_ROM_QSTR(MP_QSTR_agent_auth), MP_ROM_PTR(&sftp_agent_auth_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_execute), MP_ROM_PTR(&ssh_execute_obj) },
+    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&ssh_channel_read_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ssh_locals_dict, ssh_locals_dict_table);
+
+const mp_obj_type_t ssh_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_ussh,
+    .print = sftp_print,
+    .make_new = ssh_make_new,
+    .locals_dict = (mp_obj_dict_t *)&ssh_locals_dict,
+};
+
+
+STATIC const mp_rom_map_elem_t mp_module_ssh_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussh) },
+    { MP_ROM_QSTR(MP_QSTR_ssh), MP_ROM_PTR(&ssh_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_ssh_globals, mp_module_ssh_globals_table);
+
+const mp_obj_module_t mp_module_ussh = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&mp_module_ssh_globals,
+};
+
+#endif//MICROPY_QPY_MODULE_SSH
+#endif //MICROPY_QPY_MODULE_SFTP || //MICROPY_QPY_MODULE_SSH
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modsif.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modsif.c
new file mode 100644 (file)
index 0000000..c2afe42
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "obj.h"
+#include "objstr.h"
+#include "runtime.h"
+#include "binary.h"
+#include "objarray.h"
+
+#if MICROPY_QPY_MODULE_SIF
+
+#include "runtime.h"
+#include "gc.h"
+#include "helios_extint.h"
+#include "helios_acctimer.h"
+#include "helios_debug.h"
+#include "callbackdeal.h"
+#include "helios_gpio.h"
+
+
+#define MOD_SIF_LOG(msg, ...)      custom_log("modsif", msg, ##__VA_ARGS__)
+
+#define REC_DATA_BIT_DIRECTION 1
+
+#ifdef REC_DATA_BIT_DIRECTION
+#define DATA_BIT_DIRECTION 8
+#else
+#define DATA_BIT_DIRECTION 0
+#endif
+
+#define SYNC_TIME_NUM       100
+#define LOGIC_CYCLE_NUM     20
+
+
+#define MAX_LOW_LEVEL_NUM      100
+#define STOP_LOW_LEVEL_NUM     50
+#define STOP_HING_LEVEL_MIN_NUM        500
+#define HIGH       1
+#define LOW        0
+#define FRAME_MAX_BYTE         512
+
+#define SIF_FRAME_SYNC_LEN      25
+#define SIF_FRAME_FINISH_LEN   102
+
+#define value_in_valid_range(value, standard_value, error_value) ((value < standard_value+error_value) && (value > standard_value-error_value))
+
+typedef enum
+{           
+    SYNC_STATE = 0,       
+    DATA_REV_STATE,                
+}recv_state_e;          
+
+recv_state_e receive_state = SYNC_STATE;
+
+typedef struct _sif_recv_ctrl
+{
+       uint16_t receive_data_num;
+       uint8_t read_bit_finish;
+       uint8_t read_frame_finish;
+       uint8_t read_byte_finish;
+       uint8_t m_recv_value;
+    uint8_t m_gpio;
+       uint8_t m_recv_buffer[512];
+}sif_recv_ctrl_t;
+sif_recv_ctrl_t sif_recv_ctrl;
+
+typedef struct {
+    mp_obj_base_t base;
+       c_callback_t callback;
+} sifint_obj_t;
+sifint_obj_t sifint_obj;
+
+static uint8_t sif_send_array[FRAME_MAX_BYTE] = {0};//需要发送的数据
+ 
+typedef enum _sif_send_state
+{
+    IDLE = 0,
+       SYNC_SIGNAL,
+       SEND_DATA,
+       SEND_DATA_COMPLETE,
+}sif_send_fsm_state;
+
+typedef struct _sif_ctrl
+{
+    int m_tosc_cnt;
+    int m_bit_cnt;
+    int m_byte_cnt;
+    size_t m_gpio;
+    int m_send_length;
+    int m_tosc_per_bit;
+    uint8_t *m_send_buffer;
+}SifSendCtrl;
+
+SifSendCtrl sif_send_ctrl;
+sif_send_fsm_state state = IDLE;
+int send_acc_timer_state = 0;
+int recv_acc_timer_state = 0;
+
+uint32_t sif_tick = 0;
+APBTimer_ID sif_send_timer = 0;
+APBTimer_ID sif_recv_timer = 0;
+
+
+#define sif_turn_off()                                                                                                         \
+                       do {                                                                                                            \
+                               Helios_GPIO_SetLevel(sif_send_ctrl.m_gpio, HELIOS_LVL_LOW);     \
+                       } while (0)
+                       
+#define sif_turn_on()                                                                                                  \
+                       do {                                                                                                            \
+                               Helios_GPIO_SetLevel(sif_send_ctrl.m_gpio, HELIOS_LVL_HIGH); \
+                       } while (0)
+
+static void sif_recv_data_handle(void);
+
+void sif_tick_count_cb(unsigned int arg)
+{
+    sif_tick += 2;
+}
+
+
+void sif_send_data_handle(unsigned int arg)
+{
+       SifSendCtrl *p = &sif_send_ctrl;
+       
+    switch(state)
+    {
+               case IDLE:
+            break;
+               
+        case SYNC_SIGNAL:
+            if (p->m_tosc_cnt < SIF_FRAME_SYNC_LEN - 2) {
+                sif_turn_off();
+            } 
+                       else {
+                sif_turn_on();
+            }
+            p->m_tosc_cnt++;
+            if (p->m_tosc_cnt >= SIF_FRAME_SYNC_LEN) {
+                state = SEND_DATA;
+                p->m_tosc_cnt = 0;
+                p->m_bit_cnt = 0;
+                p->m_byte_cnt = 0;
+            }
+            break;
+        case SEND_DATA:   
+            if ((p->m_send_buffer[p->m_byte_cnt] >> p->m_bit_cnt) & 0x1) // 判断当前传输位值
+            {
+                if (p->m_tosc_cnt == 0) {
+                    sif_turn_off();
+                    p->m_tosc_cnt++;
+                }
+                else if (p->m_tosc_cnt == p->m_tosc_per_bit-1) {
+                                       p->m_tosc_cnt = 0;
+                } 
+                               else {
+                    sif_turn_on();
+                    p->m_tosc_cnt ++;
+                }
+            }
+            else 
+                       {
+                if (p->m_tosc_cnt == 0) {
+                    sif_turn_off();
+                    p->m_tosc_cnt++;
+                }
+                else if (p->m_tosc_cnt == p->m_tosc_per_bit-1) {
+                    sif_turn_on();
+                    p->m_tosc_cnt = 0;
+                } else {
+                    p->m_tosc_cnt++;
+                }
+            }
+            if (p->m_tosc_cnt == 0)
+            {
+                if (p->m_bit_cnt++ >= 7)
+                {
+                    p->m_byte_cnt++;
+                    p->m_bit_cnt = 0;
+                }
+                if (p->m_byte_cnt >= p->m_send_length)
+                {
+                    state = SEND_DATA_COMPLETE;
+                    break;
+                }
+            }
+            break;
+        case SEND_DATA_COMPLETE:
+                       if (p->m_tosc_cnt < 10) {
+                sif_turn_off();
+                p->m_tosc_cnt++;
+            }
+            else if (p->m_tosc_cnt < SIF_FRAME_FINISH_LEN+10) {
+                sif_turn_on();
+                p->m_tosc_cnt++;
+            } 
+            else {
+                p->m_tosc_cnt = 0;
+                p->m_send_length = 0;
+                memset(p->m_send_buffer, 0, FRAME_MAX_BYTE);
+                state = IDLE; 
+            }    
+            break;
+        default:
+            break;
+       }
+}
+
+uint32_t sif_get_tick(void)
+{
+    return sif_tick;
+}
+
+static uint8_t sif_read_pin_level(void) {
+    return Helios_GPIO_GetLevel(sif_recv_ctrl.m_gpio);
+}
+
+
+void call_user_callback(void)
+{
+       if (mp_sched_num_pending() < MICROPY_SCHEDULER_DEPTH)
+       {
+               st_CallBack_SIF *st_sif = malloc(sizeof(st_CallBack_SIF));
+           if(NULL != st_sif) {
+           st_sif->data_len= sif_recv_ctrl.receive_data_num;
+           st_sif->data = (uint8_t *)sif_recv_ctrl.m_recv_buffer;
+           st_sif->callback = sifint_obj.callback;
+           qpy_send_msg_to_callback_deal_thread(CALLBACK_TYPE_ID_SIF, st_sif);
+       }
+       }
+
+
+}
+
+void sif_recv_data_handle(void)
+{
+       sif_recv_ctrl_t *p_read_ctrl = &sif_recv_ctrl;
+       static uint32_t last_high_tick = 0;
+    static uint32_t last_low_tick = 0;
+       static uint32_t bit_index = 0;
+       uint32_t tick_now = 0;
+       uint32_t low_time = 0;
+    uint32_t high_time = 0;
+       uint32_t bit_value = 0;
+       uint32_t cycle_time = 0;
+
+       tick_now = sif_get_tick();
+
+       // 当定时器关闭后,再次触发外部中断,开启定时器
+       if (recv_acc_timer_state == 1)
+       {
+               recv_acc_timer_state = 0;
+               APBTimerConfig_S timer_cfg = {1, 200, sif_tick_count_cb, 0};
+               Helios_Acctimer_Start(sif_recv_timer, &timer_cfg);
+       }
+    switch (receive_state)
+    {
+        case SYNC_STATE:
+                       if (sif_read_pin_level() == LOW)
+                       {
+                               if ((tick_now>last_high_tick) && (last_high_tick>last_low_tick))
+                               {
+                                       low_time = last_high_tick - last_low_tick;
+                                       high_time = tick_now - last_high_tick;
+                                       if (low_time >= SYNC_TIME_NUM)
+                                       {
+                                               #ifdef REC_DATA_BIT_DIRECTION
+                                                       bit_index = 0;                
+                                               #else
+                                                       bit_index = 8;              
+                                               #endif
+                                               p_read_ctrl->receive_data_num = 0;
+                                               memset(&p_read_ctrl->m_recv_buffer, 0x00, sizeof(p_read_ctrl->m_recv_buffer));
+                                               receive_state = DATA_REV_STATE;
+                                       }
+                               }
+                       }
+            break;
+
+        case DATA_REV_STATE:
+                       if (sif_read_pin_level() == LOW)
+                       {
+                               if ((tick_now>last_high_tick) && (last_high_tick>last_low_tick))
+                               {
+                                       low_time = last_high_tick - last_low_tick;
+                                       high_time = tick_now - last_high_tick;
+                                       cycle_time = tick_now - last_low_tick;
+                                       if (value_in_valid_range(cycle_time, LOGIC_CYCLE_NUM, 10))
+                                       {
+                                               if (low_time > high_time)
+                                               {
+                                                       bit_value = 0;
+                                               }
+                                               else
+                                               {
+                                                       bit_value = 1;
+                                               }
+                                               #ifdef REC_DATA_BIT_DIRECTION
+                                               p_read_ctrl->m_recv_value |= (bit_value<<(bit_index));
+                                               bit_index++; 
+                                               #else
+                                               p_read_ctrl->m_recv_value |= (bit_value<<(bit_index-1));
+                                               bit_index--; 
+                                               #endif
+                                               // 接收一个byte结束
+                                               if (DATA_BIT_DIRECTION == bit_index)
+                                               {
+                                                       if (p_read_ctrl->receive_data_num < 512)
+                                                       {
+                                                               p_read_ctrl->m_recv_buffer[p_read_ctrl->receive_data_num++] = p_read_ctrl->m_recv_value;
+                                                               p_read_ctrl->m_recv_value = 0;
+                                                               #ifdef REC_DATA_BIT_DIRECTION
+                                                               bit_index = 0;                
+                                                               #else
+                                                               bit_index = 8;              
+                                                               #endif
+                                                       }
+                                                       else
+                                                       {
+                                                               receive_state = SYNC_STATE;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               if ((tick_now>last_low_tick) && (last_low_tick>last_high_tick))
+                               {
+                                       if ((tick_now-last_low_tick >= STOP_LOW_LEVEL_NUM - 10) && (tick_now-last_low_tick <= STOP_LOW_LEVEL_NUM + 20))
+                                       {
+                                               call_user_callback();
+                                               receive_state = SYNC_STATE;
+                                       }
+                               }
+                       }
+            break;
+               default:
+                       break;
+    }
+       
+       if (sif_read_pin_level() == HIGH)
+       {
+               last_high_tick = tick_now;
+       }
+       else
+       {
+               last_low_tick = tick_now;
+       }
+
+       Helios_ExtInt_Enable((Helios_GPIONum) sif_recv_ctrl.m_gpio);
+}
+
+
+static mp_obj_t sif_init(mp_obj_t gpio_in, mp_obj_t gpio_out, mp_obj_t cb)
+{
+       int ret = -1;
+
+    Helios_ExtIntStruct extint_struct = {0};
+       extint_struct.gpio_trigger = HELIOS_EDGE_TRIGGER;
+       extint_struct.gpio_edge = HELIOS_EDGE_BOTH;
+       extint_struct.gpio_debounce = HELIOS_DEBOUNCE_EN;
+       extint_struct.gpio_pull = HELIOS_PULL_UP;
+       extint_struct.eint_cb = NULL;
+       extint_struct.wakeup_eint_cb = sif_recv_data_handle;
+       
+    sif_recv_ctrl.m_gpio = mp_obj_get_int(gpio_in);
+       sif_send_ctrl.m_gpio = mp_obj_get_int(gpio_out);
+       MOD_SIF_LOG("extint gpio %d, out gpio %d", sif_recv_ctrl.m_gpio, sif_send_ctrl.m_gpio);
+       if(0 != Helios_ExtInt_Init((Helios_GPIONum) sif_recv_ctrl.m_gpio,  &extint_struct)) {
+               mp_raise_ValueError("Interrupt initialization failed");
+       }
+       Helios_ExtInt_Enable((Helios_GPIONum) sif_recv_ctrl.m_gpio);
+
+       // 初始化GPIO
+       Helios_GPIOInitStruct gpio_config;
+       gpio_config.dir = HELIOS_GPIO_OUTPUT;
+       gpio_config.pull = HELIOS_PULL_UP;      
+       gpio_config.value = HELIOS_LVL_LOW;
+       Helios_GPIO_Init(sif_send_ctrl.m_gpio, &gpio_config);
+
+       sif_send_ctrl.m_send_buffer = sif_send_array;
+
+       APBTimerConfig_S timer_cfg = {1, 200, sif_tick_count_cb, 0};
+    sif_recv_timer = Helios_Acctimer_Create(&timer_cfg); // 周期0.2ms
+    ret = Helios_Acctimer_Start(sif_recv_timer, &timer_cfg);
+
+       timer_cfg.period = 500;
+       timer_cfg.timerCallbackFunc = sif_send_data_handle;
+    sif_send_timer = Helios_Acctimer_Create(&timer_cfg); // 周期0.5ms
+    ret = Helios_Acctimer_Start(sif_send_timer, &timer_cfg);
+
+       mp_sched_schedule_callback_register(&sifint_obj.callback, cb);
+
+       return mp_obj_new_int(ret);
+}
+
+static MP_DEFINE_CONST_FUN_OBJ_3(sif_init_obj, sif_init);
+
+static mp_obj_t sif_acctimer_stop(void)
+{
+       int ret = -1;
+       send_acc_timer_state = 1;
+       recv_acc_timer_state = 1;
+       ret = Helios_Acctimer_Stop(sif_recv_timer);
+       ret = Helios_Acctimer_Stop(sif_send_timer);
+       MOD_SIF_LOG("stop acctimer");
+       return mp_obj_new_int(ret);
+}
+STATIC const MP_DEFINE_CONST_FUN_OBJ_0(sif_acctimer_stop_obj, sif_acctimer_stop);
+
+
+
+static const mp_arg_t sif_mem_allowed_args[] = {
+    { MP_QSTR_databuf,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+    { MP_QSTR_datasize,    MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+};
+
+static mp_obj_t qpy_sif_send_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
+{
+    int ret = 0;
+    enum { ARG_databuf, ARG_datatype};
+
+    mp_arg_val_t args[MP_ARRAY_SIZE(sif_mem_allowed_args)];
+    mp_arg_parse_all(n_args, pos_args, kw_args,
+        MP_ARRAY_SIZE(sif_mem_allowed_args), sif_mem_allowed_args, args);
+    
+    // get the buffer to write the data from
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(args[ARG_databuf].u_obj, &bufinfo, MP_BUFFER_READ);
+    
+    int length = bufinfo.len;
+    if ((size_t)args[ARG_datatype].u_int == 0) {
+        sif_send_ctrl.m_tosc_per_bit = 3;
+    }
+    else {
+        sif_send_ctrl.m_tosc_per_bit = 4;
+    }
+    MOD_SIF_LOG("sif send length=%d\r\n", length);
+    
+       if (state == IDLE && length < 1024 && (sif_send_ctrl.m_send_buffer != NULL))
+       {
+               memcpy(sif_send_ctrl.m_send_buffer, bufinfo.buf, length);
+               state = SYNC_SIGNAL;
+               sif_send_ctrl.m_send_length = length;
+               ret = 1;
+               // 当SIF发送定时器关掉时,此时需要打开
+               if (send_acc_timer_state == 1)
+               {
+                       send_acc_timer_state = 0;
+                       APBTimerConfig_S timer_cfg = {1, 500, sif_send_data_handle, 0};
+                       Helios_Acctimer_Start(sif_send_timer, &timer_cfg);
+               }
+       }
+       else
+       {
+               ret = 0;
+       }
+
+       return mp_obj_new_int(ret);
+}
+static MP_DEFINE_CONST_FUN_OBJ_KW(qpy_sif_send_obj, 1, qpy_sif_send_mem);
+
+
+       
+static mp_obj_t sif_test(void)
+{
+       uint8_t i = 0;
+       MOD_SIF_LOG("sif_tick %d", sif_tick);
+       return mp_obj_new_int(sif_tick);
+}
+STATIC const MP_DEFINE_CONST_FUN_OBJ_0(sif_test_obj, sif_test);
+
+
+static const mp_rom_map_elem_t modsif_globals_table[] = {
+    {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_modsif)},
+       {MP_OBJ_NEW_QSTR(MP_QSTR_init), MP_ROM_PTR(&sif_init_obj)},
+       {MP_OBJ_NEW_QSTR(MP_QSTR_test), MP_ROM_PTR(&sif_test_obj)},
+       {MP_OBJ_NEW_QSTR(MP_QSTR_acctimer_stop), MP_ROM_PTR(&sif_acctimer_stop_obj)},
+       {MP_OBJ_NEW_QSTR(MP_QSTR_send), MP_ROM_PTR(&qpy_sif_send_obj)},
+    PLAT_GPIO_DEF(PLAT_GPIO_NUM),
+};
+
+MP_DEFINE_CONST_DICT(mp_module_modsif_globals, modsif_globals_table);
+
+const mp_obj_module_t mp_module_modsif = {
+    .base = { &mp_type_module },
+       .globals = (mp_obj_dict_t *)&mp_module_modsif_globals,
+};
+
+#endif /* MICROPY_QPY_MODULE_SIF */
\ No newline at end of file
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modstk.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modstk.c
new file mode 100644 (file)
index 0000000..68da35c
--- /dev/null
@@ -0,0 +1,568 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "obj.h"
+#include "runtime.h"
+#include "helios_stk.h"
+
+#include "helios_debug.h"
+#define TITLE_TEXT_LENGTH_MAX 100
+#define QPY_MODSIM_LOG(msg, ...) custom_log("STK", msg, ##__VA_ARGS__)
+
+#if MICROPY_QPY_MODULE_STK
+
+
+#define OUT_TO_DEBUG    1
+#if OUT_TO_DEBUG
+
+#define STK_LOG(msg, ...)      custom_log(stk, msg, ##__VA_ARGS__)
+
+#else
+
+char sbuf_stk[513];
+#define STK_LOG(msg, ...) \
+{\
+    memset(sbuf_stk,0x00,512+1); \
+    snprintf(sbuf_stk,512,"[%s,%d]" msg "\n",__FUNCTION__,__LINE__,##__VA_ARGS__);\
+    mp_hal_stdout_tx_str(sbuf_stk);\
+}
+
+#endif
+
+c_callback_t stk_callback = {0};
+STATIC mp_obj_t qpy_stk_get_bip_config(void)
+{
+    helios_stk_bip_config_s bip_conf={0};
+    int ret = Helios_Stk_Get_Bip_Config(&bip_conf);
+    mp_obj_t ret_obj = mp_const_none;
+    if (ret == 0)
+    {
+        ret_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(ret_obj, mp_obj_new_int(bip_conf.status_report));
+        mp_obj_list_append(ret_obj, mp_obj_new_int(bip_conf.mode));
+        mp_obj_list_append(ret_obj, mp_obj_new_int(bip_conf.cid));
+        return ret_obj;
+    }
+    return ret_obj;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_stk_get_bip_config_obj, qpy_stk_get_bip_config);
+
+STATIC mp_obj_t qpy_stk_set_bip_config(mp_obj_t status_report, mp_obj_t mode, mp_obj_t cid)
+{
+    helios_stk_bip_config_s bip_conf={0};
+    if ( !mp_obj_is_int(status_report) || !mp_obj_is_int(mode) || !mp_obj_is_int(cid) ){
+        return mp_obj_new_int(-2);
+    }
+    bip_conf.status_report = mp_obj_get_int(status_report);
+    bip_conf.cid = mp_obj_get_int(cid);
+    bip_conf.mode = (helios_stk_bip_config_mode_e)mp_obj_get_int(mode);
+    if ( bip_conf.mode < 0 || bip_conf.mode >2 ){
+        return mp_obj_new_int(-2);
+    }
+    int ret = Helios_Stk_Set_Bip_Config(bip_conf);
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_stk_set_bip_config_obj, qpy_stk_set_bip_config);
+
+static void qpy_stk_callback_handle(uint8_t nSim, uint32_t ind_type, void *ctx){
+    STK_LOG("%d,%x,%p",nSim,ind_type,ctx);
+    if ( stk_callback.cb ){
+        mp_obj_t event=mp_obj_new_list(0,NULL);
+        mp_obj_list_append(event,mp_obj_new_int_from_uint(nSim));
+        mp_obj_list_append(event,mp_obj_new_int_from_uint(ind_type));
+        mp_obj_list_append(event,mp_obj_new_int((int)ctx));
+        GC_STACKTOP_SET();
+           mp_sched_schedule_ex(&stk_callback, event);
+           GC_STACKTOP_CLEAR();
+    }
+}
+
+STATIC mp_obj_t qpy_stk_register_cb(mp_obj_t handler)
+{
+    mp_sched_schedule_callback_register(&stk_callback, handler);
+    int ret = Helios_Stk_Register_Cb(qpy_stk_callback_handle);
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_stk_register_cb_obj, qpy_stk_register_cb);
+
+STATIC mp_obj_t qpy_stk_cfg_get(void)
+{
+    helios_stk_mode_e stk_mode;
+    helios_stk_alphabet_set_e alphabet_type;
+    uint16_t auto_response_timeout;
+    int ret = Helios_Stk_Cfg_Get(&stk_mode,&alphabet_type,&auto_response_timeout);
+    if (ret == 0)
+    {
+        mp_obj_t ret_obj=mp_obj_new_list(0,NULL);
+        if ( ret_obj == MP_OBJ_NULL )
+        {
+            return mp_const_none;
+        }
+        mp_obj_list_append(ret_obj, mp_obj_new_int(stk_mode));
+        mp_obj_list_append(ret_obj, mp_obj_new_int((uint32_t)alphabet_type));
+        mp_obj_list_append(ret_obj, mp_obj_new_int(auto_response_timeout));
+        return ret_obj;
+    }
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_stk_cfg_get_obj, qpy_stk_cfg_get);
+
+STATIC mp_obj_t qpy_stk_cfg_set(mp_obj_t mode, mp_obj_t alphabet_type, mp_obj_t auto_response_timeout)
+{
+    if ( !mp_obj_is_int(mode) || !mp_obj_is_int(alphabet_type) || !mp_obj_is_int(auto_response_timeout) ){
+        return mp_obj_new_int(-2);
+    }
+    helios_stk_mode_e stk_mode = mp_obj_get_int(mode);
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e)mp_obj_get_int(alphabet_type);
+    uint16_t auto_timeout= mp_obj_get_int(auto_response_timeout);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        return mp_obj_new_int(-2);
+    }
+    int ret = Helios_Stk_Cfg_Set(stk_mode,alphabet,auto_timeout);
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_stk_cfg_set_obj, qpy_stk_cfg_set);
+
+STATIC mp_obj_t qpy_stk_get_terminal_profile(mp_obj_t nSim)
+{
+    if ( !mp_obj_is_int(nSim) ){
+        return mp_const_none;
+    }
+    uint8_t nSim_id = mp_obj_get_int(nSim);
+    helios_stk_profile_s profile_config;
+    mp_obj_t ret_obj = mp_const_none;
+    int ret = Helios_Stk_Get_Terminal_Profile(nSim_id,&profile_config);
+    if (ret == 0)
+    {
+        return mp_obj_new_str((char *)profile_config.profile_buf,profile_config.profile_len);
+    }
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_stk_get_terminal_profile_obj, qpy_stk_get_terminal_profile);
+
+STATIC mp_obj_t qpy_stk_acquire_setup_menu_info(const mp_obj_t sim_id, const mp_obj_t alphabet_mode)
+{
+    helios_stk_setup_menu_s menu_info ={0};
+    if( !mp_obj_is_int(sim_id) || !mp_obj_is_int(alphabet_mode) ){
+        return mp_const_none;
+    }
+    uint8_t nSim = mp_obj_get_int(sim_id);
+    menu_info.title.length = HELIOS_STK_STRING_LENGTH_MAX;
+    menu_info.title.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( menu_info.title.text == NULL ){
+        QPY_MODSIM_LOG("calloc failed");
+        return mp_const_none;
+    }
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e) mp_obj_get_int(alphabet_mode);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        free(menu_info.title.text);
+        return mp_const_none;
+    }
+    int ret = Helios_Stk_Acquire_Setup_Menu_Info(nSim, &menu_info,alphabet);
+    if ( ret == 0 ){
+        mp_obj_t ret_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(ret_obj,mp_obj_new_int(menu_info.qualifier));
+        mp_obj_list_append(ret_obj,mp_obj_new_str((char *)menu_info.title.text,menu_info.title.length));
+        
+        if ( menu_info.num_items != 0 ){
+            uint32_t item_nums = 0;
+            mp_obj_t ret_sub_obj = mp_obj_new_list(0,NULL);
+            for ( item_nums = 0 ; item_nums < menu_info.num_items;item_nums++ ){
+                mp_obj_list_append(ret_sub_obj,mp_obj_new_int(menu_info.item_id[item_nums]));
+            }
+            mp_obj_list_append(ret_obj,ret_sub_obj);
+        }
+        free(menu_info.title.text);
+        return ret_obj;
+    }
+    free(menu_info.title.text);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_stk_acquire_setup_menu_infol_obj, qpy_stk_acquire_setup_menu_info);
+
+STATIC mp_obj_t qpy_stk_acquire_setup_menu_item_list(const mp_obj_t nSim_id, const mp_obj_t item_id, const mp_obj_t alphabet_mode)
+{
+    if( !mp_obj_is_int(nSim_id) || !mp_obj_is_int(alphabet_mode) || !mp_obj_is_int(item_id)  ){
+        return mp_const_none;
+    }
+    uint8_t nSim = mp_obj_get_int(nSim_id);
+    uint8_t item_identifler = mp_obj_get_int(item_id);
+    helios_stk_item_s item_info = {0};
+    
+    item_info.item_text.length = HELIOS_STK_STRING_LENGTH_MAX;
+    item_info.item_text.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( item_info.item_text.text == NULL ){
+        QPY_MODSIM_LOG("calloc failed");
+        return  mp_const_none;
+    }
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e) mp_obj_get_int(alphabet_mode);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        free(item_info.item_text.text);
+        return mp_const_none;
+    }
+    int ret = Helios_Stk_Acquire_Setup_Menu_Item_List( nSim, item_identifler, &item_info, alphabet);
+    if (ret == 0)
+    {
+        mp_obj_t res_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(res_obj,mp_obj_new_int(item_info.item_id));
+        mp_obj_list_append(res_obj,mp_obj_new_str((char *)item_info.item_text.text,item_info.item_text.length));
+        free(item_info.item_text.text);
+        return res_obj;
+    }
+    free(item_info.item_text.text);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_stk_acquire_setup_menu_item_list_obj,  qpy_stk_acquire_setup_menu_item_list);
+
+STATIC mp_obj_t qpy_stk_acquire_sub_menu_info(const mp_obj_t nSim_id,const mp_obj_t alphabet_mode)
+{
+    if( !mp_obj_is_int(nSim_id) || !mp_obj_is_int(alphabet_mode) ){
+        return mp_const_none;
+    }
+    uint8_t nSim = mp_obj_get_int(nSim_id);
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e) mp_obj_get_int(alphabet_mode);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        return mp_const_none;
+    }
+    helios_stk_select_item_s  sub_menu_info = {0};
+    sub_menu_info.title.length = HELIOS_STK_STRING_LENGTH_MAX;
+    sub_menu_info.title.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( sub_menu_info.title.text == NULL ){
+        QPY_MODSIM_LOG("calloc failed");
+        return  mp_const_none;
+    }
+    int ret = Helios_Stk_Acquire_Sub_Menu_Info( nSim,&sub_menu_info,alphabet);
+    if (ret == 0)
+    {
+        mp_obj_t ret_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(ret_obj,mp_obj_new_int(sub_menu_info.qualifier));
+        mp_obj_list_append(ret_obj,mp_obj_new_str((char *)sub_menu_info.title.text,sub_menu_info.title.length));
+        
+        if ( sub_menu_info.num_items != 0 ){
+            uint32_t item_nums = 0;
+            mp_obj_t ret_sub_obj = mp_obj_new_list(0,NULL);
+            for ( item_nums = 0 ; item_nums < sub_menu_info.num_items;item_nums++ ){
+                mp_obj_list_append(ret_sub_obj,mp_obj_new_int(sub_menu_info.item_id[item_nums]));
+            }
+            mp_obj_list_append(ret_obj,ret_sub_obj);
+        }
+        free(sub_menu_info.title.text);
+        return ret_obj;
+        
+    }
+    free(sub_menu_info.title.text);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_stk_acquire_sub_menu_info_obj,qpy_stk_acquire_sub_menu_info);
+
+STATIC mp_obj_t qpy_stk_acquire_sub_menu_item_list(const mp_obj_t nSim_id, const mp_obj_t item_id, const mp_obj_t alphabet_mode)
+{
+    if( !mp_obj_is_int(nSim_id) || !mp_obj_is_int(alphabet_mode) || !mp_obj_is_int(item_id)  ){
+        return mp_const_none;
+    }
+    uint8_t nSim = mp_obj_get_int(nSim_id);
+    uint8_t item_identifler = mp_obj_get_int(item_id);
+    helios_stk_item_s item_info = {0};
+    
+    item_info.item_text.length = HELIOS_STK_STRING_LENGTH_MAX;
+    item_info.item_text.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( item_info.item_text.text == NULL ){
+        QPY_MODSIM_LOG("calloc failed");
+        return  mp_const_none;
+    }
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e) mp_obj_get_int(alphabet_mode);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        free(item_info.item_text.text);
+        return mp_const_none;
+    }
+    int ret = Helios_Stk_Acquire_Sub_Menu_Item_List( nSim, item_identifler, &item_info, alphabet);
+    if (ret == 0)
+    {
+        mp_obj_t res_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(res_obj,mp_obj_new_int(item_info.item_id));
+        mp_obj_list_append(res_obj,mp_obj_new_str((char *)item_info.item_text.text,item_info.item_text.length));
+        free(item_info.item_text.text);
+        return res_obj;
+    }
+    free(item_info.item_text.text);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_stk_acquire_sub_menu_item_list_obj,  qpy_stk_acquire_sub_menu_item_list);
+
+STATIC mp_obj_t qpy_stk_acquire_display_text_info(const mp_obj_t nSim_id,const mp_obj_t alphabet_mode)
+{
+    if( !mp_obj_is_int(nSim_id) || !mp_obj_is_int(alphabet_mode) ){
+        return mp_const_none;
+    }
+    uint8_t nSim = mp_obj_get_int(nSim_id);
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e) mp_obj_get_int(alphabet_mode);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        return mp_const_none;
+    }
+    helios_stk_display_text_s display_text = {0};
+    display_text.text_string.length = HELIOS_STK_STRING_LENGTH_MAX;
+    display_text.text_string.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( display_text.text_string.text == NULL ){
+        QPY_MODSIM_LOG("calloc failed");
+        return  mp_const_none;
+    }
+    int ret = Helios_Stk_Acquire_Display_Text_Info( nSim, &display_text, alphabet);
+    if ( ret == 0 )
+    {
+        mp_obj_t res_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(res_obj,mp_obj_new_int(display_text.qualifier));
+        mp_obj_list_append(res_obj,mp_obj_new_str((char *)display_text.text_string.text,display_text.text_string.length));
+        free(display_text.text_string.text);
+        return res_obj;
+    }
+    free(display_text.text_string.text);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_stk_acquire_display_text_info_obj,  qpy_stk_acquire_display_text_info);
+
+STATIC mp_obj_t qpy_stk_acquire_get_input_info(const mp_obj_t nSim_id,const mp_obj_t alphabet_mode)
+{
+   
+    if( !mp_obj_is_int(nSim_id) || !mp_obj_is_int(alphabet_mode) ){
+        return mp_const_none;
+    }
+    uint8_t nSim = mp_obj_get_int(nSim_id);
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e) mp_obj_get_int(alphabet_mode);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        return mp_const_none;
+    }
+    helios_stk_get_input_s display_text = {0};
+    display_text.text_string.length = HELIOS_STK_STRING_LENGTH_MAX;
+    display_text.default_text.length = HELIOS_STK_STRING_LENGTH_MAX;
+    display_text.text_string.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( display_text.text_string.text == NULL ){
+        QPY_MODSIM_LOG("calloc failed");
+        return  mp_const_none;
+    }
+    display_text.default_text.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( display_text.text_string.text == NULL ){
+        QPY_MODSIM_LOG("calloc failed");
+        free(display_text.text_string.text);
+        return  mp_const_none;
+    }
+    int ret = Helios_Stk_Acquire_Get_Input_Info( nSim, &display_text, alphabet);
+    if ( ret == 0 )
+    {
+        mp_obj_t res_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(res_obj,mp_obj_new_int(display_text.qualifier));
+        mp_obj_list_append(res_obj,mp_obj_new_int(display_text.minimum_user_input));
+        mp_obj_list_append(res_obj,mp_obj_new_int(display_text.maximum_user_input));
+        mp_obj_list_append(res_obj,mp_obj_new_str((char *)display_text.text_string.text,display_text.text_string.length));
+        mp_obj_list_append(res_obj,mp_obj_new_str((char *)display_text.default_text.text,display_text.default_text.length));
+        free(display_text.text_string.text);
+        free(display_text.default_text.text);
+        return res_obj;
+    }
+    free(display_text.text_string.text);
+    free(display_text.default_text.text);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_stk_acquire_get_input_info_obj,  qpy_stk_acquire_get_input_info);
+
+STATIC mp_obj_t qpy_stk_acquire_get_inkey_info(const mp_obj_t nSim_id,const mp_obj_t alphabet_mode)
+{
+    if( !mp_obj_is_int(nSim_id) || !mp_obj_is_int(alphabet_mode) ){
+        return mp_const_none;
+    }
+    uint8_t nSim = mp_obj_get_int(nSim_id);
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e) mp_obj_get_int(alphabet_mode);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        return mp_const_none;
+    }
+    helios_stk_get_inkey_s  inkey_info = {0};
+    inkey_info.text_string.length = HELIOS_STK_STRING_LENGTH_MAX;
+    inkey_info.text_string.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( NULL == inkey_info.text_string.text ){
+        QPY_MODSIM_LOG("calloc failed");
+        return  mp_const_none;
+    }
+    int ret = Helios_Stk_Acquire_Get_Inkey_Info( nSim, &inkey_info, alphabet);
+    if ( ret == 0 )
+    {
+        mp_obj_t res_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(res_obj,mp_obj_new_int(inkey_info.qualifier));
+        mp_obj_list_append(res_obj,mp_obj_new_str((char *)inkey_info.text_string.text,inkey_info.text_string.length));
+        free(inkey_info.text_string.text);
+        return res_obj;
+    }
+    free(inkey_info.text_string.text);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_stk_acquire_get_inkey_info_obj,  qpy_stk_acquire_get_inkey_info);
+
+STATIC mp_obj_t qpy_stk_acquire_setup_idle_mode_text_info(const mp_obj_t nSim_id,const mp_obj_t alphabet_mode)
+{
+    if( !mp_obj_is_int(nSim_id) || !mp_obj_is_int(alphabet_mode) ){
+        return mp_const_none;
+    }
+    uint8_t nSim = mp_obj_get_int(nSim_id);
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e) mp_obj_get_int(alphabet_mode);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        return mp_const_none;
+    }
+    helios_stk_setup_idle_mode_text_s inkey_info={0};
+    inkey_info.text_string.length = HELIOS_STK_STRING_LENGTH_MAX;
+    inkey_info.text_string.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( NULL == inkey_info.text_string.text ){
+        QPY_MODSIM_LOG("calloc failed");
+        return  mp_const_none;
+    }
+    int ret = Helios_Stk_Acquire_Setup_Idle_Mode_Text_Info( nSim, &inkey_info, alphabet);
+    if ( ret == 0 )
+    {
+        mp_obj_t res_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(res_obj,mp_obj_new_int(inkey_info.qualifier));
+        mp_obj_list_append(res_obj,mp_obj_new_str((char *)inkey_info.text_string.text,inkey_info.text_string.length));
+        free(inkey_info.text_string.text);
+        return res_obj;
+    }
+    free(inkey_info.text_string.text);
+    return  mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_stk_acquire_setup_idle_mode_text_info_obj, qpy_stk_acquire_setup_idle_mode_text_info);
+
+STATIC mp_obj_t qpy_stk_acquire_language_notification_info(const mp_obj_t nSim_id)
+{
+    if( !mp_obj_is_int(nSim_id)){
+        return mp_const_none;
+    }
+    helios_stk_language_notification_s notification_info = {0};
+    uint8_t nSim = mp_obj_get_int(nSim_id);
+    int ret = Helios_Stk_Acquire_Language_Notification_Info(nSim, &notification_info);
+    if ( ret == 0 )
+    {
+        mp_obj_t res_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(res_obj,mp_obj_new_int(notification_info.qualifier));
+        mp_obj_list_append(res_obj,mp_obj_new_str((char *)notification_info.language.alpha2,2));
+        return res_obj;
+    }
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_stk_acquire_language_notification_info_obj,qpy_stk_acquire_language_notification_info);
+
+STATIC mp_obj_t qpy_stk_acquire_play_tone_info(const mp_obj_t nSim_id,const mp_obj_t alphabet_mode)
+{
+    if( !mp_obj_is_int(nSim_id) || !mp_obj_is_int(alphabet_mode) ){
+        return mp_const_none;
+    }
+    uint8_t nSim = mp_obj_get_int(nSim_id);
+    helios_stk_play_tone_s tone_info = {0};
+    helios_stk_alphabet_set_e alphabet = (helios_stk_alphabet_set_e) mp_obj_get_int(alphabet_mode);
+    if ( alphabet !=HELIOS_STK_ALPHABET_SET_GSM && alphabet !=HELIOS_STK_ALPHABET_SET_UCS2 ){
+        return mp_const_none;
+    }
+    tone_info.title.length = HELIOS_STK_STRING_LENGTH_MAX;
+    tone_info.title.text = calloc(1,HELIOS_STK_STRING_LENGTH_MAX+1);
+    if ( NULL == tone_info.title.text ){
+        QPY_MODSIM_LOG("calloc failed");
+        return  mp_const_none;
+    }
+    int ret = Helios_Stk_Acquire_Play_Tone_Info( nSim, &tone_info, alphabet);
+    if ( ret == 0 )
+    {
+        mp_obj_t res_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(res_obj,mp_obj_new_int(tone_info.qualifier));
+        mp_obj_list_append(res_obj,mp_obj_new_int((uint32_t)tone_info.tone));
+        mp_obj_list_append(res_obj,mp_obj_new_int(tone_info.duration_unit));
+        mp_obj_list_append(res_obj,mp_obj_new_int(tone_info.duration));
+        mp_obj_list_append(res_obj,mp_obj_new_str((char *)tone_info.title.text,tone_info.title.length));
+        free(tone_info.title.text);
+        return res_obj;
+    }
+    free(tone_info.title.text);
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_stk_acquire_play_tone_info_obj,  qpy_stk_acquire_play_tone_info);
+
+STATIC mp_obj_t qpy_stk_send_command_result(size_t n_args, const mp_obj_t *args)
+{
+    if( !mp_obj_is_int(args[0]) || !mp_obj_is_int(args[1]) || !mp_obj_is_int(args[2]) || !mp_obj_is_int(args[3]) ){
+        return mp_obj_new_int(-2);
+    }
+    uint8_t nSim        = mp_obj_get_int(args[0]);
+    uint8_t stk_cmd_id  = mp_obj_get_int(args[1]);
+    uint8_t result      = mp_obj_get_int(args[2]);
+    uint8_t item_id     = mp_obj_get_int(args[3]);
+    int ret = 0;
+    if ( n_args == 4 ){
+        ret = Helios_Stk_Send_Command_Result(nSim,stk_cmd_id,result,item_id,NULL);
+    }else{
+        if ( !mp_obj_is_str(args[4]) ){
+            return mp_obj_new_int(-2);
+        }
+        size_t len = 0;
+        helios_stk_string_s res_string = {0};
+        res_string.text    = (uint8_t*)mp_obj_str_get_data(args[4], &len);
+        res_string.length = (uint16_t)len;
+        ret = Helios_Stk_Send_Command_Result(nSim,stk_cmd_id,result,item_id,&res_string);
+    }
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qpy_stk_send_command_result_obj, 4, 5,qpy_stk_send_command_result);
+
+STATIC mp_obj_t qpy_stk_get_stk_proactive_cmd(const mp_obj_t nSim_id)
+{
+    if( !mp_obj_is_int(nSim_id) ){
+        return mp_const_none;
+    }
+    uint8_t nSim        = mp_obj_get_int(nSim_id);
+    helios_stk_proactive_cmd_e  ret_cmd;
+    helios_stk_state_e  ret_state;
+    int ret = Helios_Stk_Get_Stk_Proactive_Cmd(nSim, &ret_cmd, &ret_state);
+    if ( ret == 0 )
+    {
+        mp_obj_t res_obj = mp_obj_new_list(0,NULL);
+        mp_obj_list_append(res_obj,mp_obj_new_int((uint32_t)ret_cmd));
+        mp_obj_list_append(res_obj,mp_obj_new_int((uint32_t)ret_state));
+        return res_obj;
+    }
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_stk_get_stk_proactive_cmd_obj,  qpy_stk_get_stk_proactive_cmd);
+
+STATIC void qpy_module_stk_deinit(void){
+    Helios_Stk_Register_Cb(NULL);
+    stk_callback.cb = NULL;
+    return ;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_module_stk_del_obj, qpy_module_stk_deinit);
+
+/* 定义的stk全局字典,之后我们添加type和function就要添加在这里 */
+STATIC const mp_rom_map_elem_t stk_globals_table[] = {
+    {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_stk)},
+    {MP_ROM_QSTR(MP_QSTR_get_bip_conf), MP_ROM_PTR(&qpy_stk_get_bip_config_obj)},
+    {MP_ROM_QSTR(MP_QSTR_set_bip_conf), MP_ROM_PTR(&qpy_stk_set_bip_config_obj)},
+    {MP_ROM_QSTR(MP_QSTR_register_cb), MP_ROM_PTR(&qpy_stk_register_cb_obj)},
+    {MP_ROM_QSTR(MP_QSTR_get_conf), MP_ROM_PTR(&qpy_stk_cfg_get_obj)},
+    {MP_ROM_QSTR(MP_QSTR_set_conf), MP_ROM_PTR(&qpy_stk_cfg_set_obj)},
+    {MP_ROM_QSTR(MP_QSTR_get_terminal_profile), MP_ROM_PTR(&qpy_stk_get_terminal_profile_obj)},
+    {MP_ROM_QSTR(MP_QSTR_setup_menu_info), MP_ROM_PTR(&qpy_stk_acquire_setup_menu_infol_obj)},
+    {MP_ROM_QSTR(MP_QSTR_setup_menu_item), MP_ROM_PTR(&qpy_stk_acquire_setup_menu_item_list_obj)},
+    {MP_ROM_QSTR(MP_QSTR_submenu_info), MP_ROM_PTR(&qpy_stk_acquire_sub_menu_info_obj)},
+    {MP_ROM_QSTR(MP_QSTR_submenu_item), MP_ROM_PTR(&qpy_stk_acquire_sub_menu_item_list_obj)},
+    {MP_ROM_QSTR(MP_QSTR_get_input_info), MP_ROM_PTR(&qpy_stk_acquire_get_input_info_obj)},
+    {MP_ROM_QSTR(MP_QSTR_get_inkey_info), MP_ROM_PTR(&qpy_stk_acquire_get_inkey_info_obj)},
+    {MP_ROM_QSTR(MP_QSTR_setup_idle_mode_text_info), MP_ROM_PTR(&qpy_stk_acquire_setup_idle_mode_text_info_obj)},
+    {MP_ROM_QSTR(MP_QSTR_language_notification_info), MP_ROM_PTR(&qpy_stk_acquire_language_notification_info_obj)},
+    {MP_ROM_QSTR(MP_QSTR_play_tone_info), MP_ROM_PTR(&qpy_stk_acquire_play_tone_info_obj)},
+    {MP_ROM_QSTR(MP_QSTR_send_command_result), MP_ROM_PTR(&qpy_stk_send_command_result_obj)},
+    {MP_ROM_QSTR(MP_QSTR_get_proactive_cmd), MP_ROM_PTR(&qpy_stk_get_stk_proactive_cmd_obj)},
+    {MP_ROM_QSTR(MP_QSTR_display_text_info), MP_ROM_PTR(&qpy_stk_acquire_display_text_info_obj)},
+    {MP_ROM_QSTR(MP_QSTR___stk_del__),   MP_ROM_PTR(&qpy_module_stk_del_obj) },
+};
+
+/* 把stk_globals_table注册到 mp_module_stk_globals里面去 */
+STATIC MP_DEFINE_CONST_DICT(mp_module_stk_globals, stk_globals_table);
+
+/* 定义一个module类型 */
+const mp_obj_module_t mp_module_stk = {
+    .base = {&mp_type_module},
+    .globals = (mp_obj_dict_t *)&mp_module_stk_globals,
+};
+
+#endif
\ No newline at end of file
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modussd.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modussd.c
new file mode 100644 (file)
index 0000000..d18b5f4
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "obj.h"
+#include "runtime.h"
+#include "mphalport.h"
+
+// #define MICROPY_QPY_MODULE_USSD             (1)
+
+#if MICROPY_QPY_MODULE_USSD
+
+#include "helios_debug.h"
+#include "helios_ussd.h"
+#include "helios_sim.h"
+
+
+#define QPY_MODUSSD_LOG(msg, ...)      custom_log("USSD", msg, ##__VA_ARGS__)
+extern int _get_current_simid(void);
+
+static c_callback_t *g_ussd_user_callback = NULL;
+
+
+static void qpy_ussd_event_handler(uint8_t sim_id, unsigned int ind_type, void *ctx)
+{
+       Helios_Ussd_str_s *ussd_str = (Helios_Ussd_str_s *)ctx;
+       uint8_t helios_ussd_buffer[QUEC_SS_USSD_UCS2_SIZE_MAX+1] = {0};
+       int str_len = 0;
+       int error = 0;
+       if(HELIOS_USSD_RESP_SUCCESS == ussd_str->resp_type)
+       {
+               if(0 < ussd_str->len) {
+                       str_len= (ussd_str->len > QUEC_SS_USSD_UCS2_SIZE_MAX) ? QUEC_SS_USSD_UCS2_SIZE_MAX : ussd_str->len;
+                       memcpy((void*)helios_ussd_buffer,(void*)ussd_str->str,str_len);
+               }
+       }
+       if (ussd_str->err_code != HELIOS_UNKNOWN){
+               error = ussd_str->err_code;
+       }else {
+               error = ind_type;
+       }
+       if (g_ussd_user_callback) {
+               QPY_MODUSSD_LOG("[ussd] callback start.\r\n");
+               MP_THREAD_GIL_ENTER();
+               GC_STACKTOP_SET();
+               mp_obj_t tuple[4] = 
+               {
+                       mp_obj_new_int(ussd_str->resp_type),
+                       mp_obj_new_str((char *)helios_ussd_buffer, str_len), 
+                       mp_obj_new_int(ussd_str->dcs),
+                       mp_obj_new_int(error),
+               };
+               mp_sched_schedule_ex(g_ussd_user_callback, mp_obj_new_tuple(4, tuple));
+               GC_STACKTOP_CLEAR();
+               MP_THREAD_GIL_EXIT();
+               QPY_MODUSSD_LOG("[ussd] callback end.\r\n");
+       }
+       return;
+}
+
+STATIC mp_obj_t qpy_ussd_add_callback(mp_obj_t handler)
+{
+       int cur_simid = _get_current_simid();
+       static c_callback_t cb = {0};
+    memset(&cb, 0, sizeof(c_callback_t));
+       g_ussd_user_callback = &cb;
+       mp_sched_schedule_callback_register(g_ussd_user_callback, handler);
+       Helios_UssdInitStruct info;
+    memset(&info, 0, sizeof(Helios_UssdInitStruct));
+       info.user_cb = qpy_ussd_event_handler;
+       Helios_Ussd_Init(cur_simid,&info);
+       return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_ussd_add_callback_obj, qpy_ussd_add_callback);
+
+
+STATIC mp_obj_t qpy_ussd_get_dcs(void)
+{
+       int cur_simid = _get_current_simid();
+       uint8_t dcs = 15;
+       if (0 != Helios_Ussd_GetDcs(cur_simid,&dcs)) {
+               return mp_obj_new_int(-1);
+       }
+       return mp_obj_new_int(dcs);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_ussd_get_dcs_obj, qpy_ussd_get_dcs);
+
+
+STATIC mp_obj_t qpy_ussd_set_dcs(mp_obj_t dcs_type)
+{
+       int dcs = mp_obj_get_int(dcs_type);
+       int simid = _get_current_simid();
+
+       if (0 != Helios_Ussd_SetDcs(simid,dcs)) {
+               return mp_obj_new_int(-1);
+       }
+       return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_ussd_set_dcs_obj, qpy_ussd_set_dcs);
+
+
+STATIC mp_obj_t qpy_ussd_get_session_state(void)
+{      
+       int simid = _get_current_simid();
+       bool state = false;
+       if (0 != Helios_Ussd_GetSessionState(simid,&state)) {
+               return mp_obj_new_int(-1);
+       }
+       return mp_obj_new_bool(state);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_ussd_get_session_state_obj, qpy_ussd_get_session_state);
+
+
+STATIC mp_obj_t qpy_ussd_send(mp_obj_t req_da)
+{
+       int ret =0;
+    mp_buffer_info_t reqstr = {0};
+    mp_get_buffer_raise(req_da, &reqstr, MP_BUFFER_READ);
+       if (reqstr.len >= QUEC_SS_USSD_STRING_SIZE_MAX){
+               mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("invalid value, the length of reqstr should be no more than [%d] bytes."), QUEC_SS_USSD_STRING_SIZE_MAX);
+       }
+       int simid = _get_current_simid();
+       uint8_t option = HELIOS_USSD_SESSION_INITIATE;
+       if (0 != Helios_Ussd_Send(simid, option,(char *)reqstr.buf)){
+               ret =-1;
+       }
+       return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_ussd_send_obj, qpy_ussd_send);
+
+
+STATIC mp_obj_t qpy_ussd_stop_session(void)
+{
+       int simid = _get_current_simid();
+       bool state = false;
+       if (0 != Helios_Ussd_GetSessionState(simid,&state) || !state) {
+               return mp_obj_new_int(-1);
+       }
+       Helios_Ussd_send_s send_info = {0};
+       uint8_t option = HELIOS_USSD_SESSION_CANCEL;
+       if (0 != Helios_Ussd_Send(simid,option, NULL)){
+               return mp_obj_new_int(-1);
+       }
+       return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_ussd_stop_session_obj, qpy_ussd_stop_session);
+
+
+
+
+STATIC mp_obj_t qpy_module_ussd_deinit(void)
+{
+       g_ussd_user_callback = NULL;
+       Helios_Ussd_Deinit();
+       return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_module_ussd_deinit_obj, qpy_module_ussd_deinit);
+
+
+
+STATIC const mp_rom_map_elem_t mp_module_ussd_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__),                           MP_ROM_QSTR(MP_QSTR_ussd) },
+    { MP_ROM_QSTR(MP_QSTR___qpy_module_deinit__),   MP_ROM_PTR(&qpy_module_ussd_deinit_obj) },
+    { MP_ROM_QSTR(MP_QSTR_getDcs),                     MP_ROM_PTR(&qpy_ussd_get_dcs_obj) },
+    { MP_ROM_QSTR(MP_QSTR_setDcs),                             MP_ROM_PTR(&qpy_ussd_set_dcs_obj) },
+    { MP_ROM_QSTR(MP_QSTR_send),                                       MP_ROM_PTR(&qpy_ussd_send_obj) },
+    { MP_ROM_QSTR(MP_QSTR_stopSession),            MP_ROM_PTR(&qpy_ussd_stop_session_obj) },
+    { MP_ROM_QSTR(MP_QSTR_getSessionState),            MP_ROM_PTR(&qpy_ussd_get_session_state_obj) },
+       { MP_ROM_QSTR(MP_QSTR_setCallback),                     MP_ROM_PTR(&qpy_ussd_add_callback_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(mp_module_ussd_globals, mp_module_ussd_globals_table);
+
+
+const mp_obj_module_t mp_module_ussd = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&mp_module_ussd_globals,
+};
+
+#endif /* MICROPY_QPY_MODULE_USSD */
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modvoip.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modvoip.c
new file mode 100644 (file)
index 0000000..7410e81
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ /**
+ @file modvoicecall.h
+*/
+/**************************************************************************
+===========================================================================
+Copyright (c) 2021 Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+Quectel Wireless Solution Proprietary and Confidential.
+===========================================================================
+
+                                               EDIT HISTORY FOR FILE
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+WHEN           WHO                     WHAT,WHERE,WHY
+----------  ---------   ---------------------------------------------------
+2021/07/20  Mia.zhong  Create.
+**************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "obj.h"
+#include "runtime.h"
+#include "mphalport.h"
+#include "mperrno.h"
+
+#if MICROPY_QPY_MODULE_VOIP
+
+#include "helios_debug.h"
+#include "osip2/osip_mt.h"
+#include "eXosip2/eXosip.h"
+#include "media_audio.h"
+#include "rtp.h"
+#include "sockets.h"
+#include "random.h"
+#include "helios_datacall.h"
+
+
+#define QUECPPYTHON_PROG_NAME "quecpython"
+
+#include "callbackdeal.h"
+
+
+#define QPY_MODVOIP_LOG(msg, ...)      custom_log("VOIP", msg, ##__VA_ARGS__)
+
+typedef struct _machine_pcm_obj_t {
+    mp_obj_base_t base;
+       void* handle_read;
+       void* handle_write;
+       int mic_channel;
+    unsigned int channels;
+    unsigned int samplerate;
+       unsigned int flags;
+} machine_pcm_obj_t;
+
+
+typedef struct _G711_obj_t {
+       mp_obj_base_t base;
+       machine_pcm_obj_t pcm_handler;
+}G711_obj_t;
+
+
+typedef struct regparam_t {
+  int regid;
+  int expiry;
+  int auth;
+} regparam_t;
+
+typedef enum {
+    HELIOS_VOIP_UDP = 0,
+    HELIOS_VOIP_TCP,
+    HELIOS_VOIP_TLS,
+    HELIOS_VOIP_DTLS,
+    HELIOS_WLAN_MODE_MAX,
+} Helios_Voip_transfer_proto_e;
+
+
+typedef struct _voip_client_t {
+       char username[32];
+       char password[32];
+       char serverip[256];
+       int server_port;
+       char localip[32];
+       int local_port;
+       Helios_Voip_transfer_proto_e proto;
+       int keepalive;
+} _voip_client_t;
+
+/* 定义wlan_obj_t结构体 */
+typedef struct _voip_obj_t {
+    mp_obj_base_t base;
+       _voip_client_t client;
+    c_callback_t voip_event_callback;
+       struct eXosip_t *context_eXosip;
+       media_param_t media;
+       Helios_Thread_t voip_main_task;
+       int call_id;
+       int dialog_id;
+} voip_obj_t;
+
+const mp_obj_type_t mp_voip_type;
+static voip_obj_t *voip = NULL;
+static volatile int keepRunning = 1;
+
+static int sdp_complete_200ok(osip_message_t *sip)
+{
+    int i = 0;
+    uint32_t random = 0;
+    char local_sdp[512] = {0};
+    char ip4_addr_str[16] = {0};
+    Helios_DataCallInfoStruct info = {0};
+
+    random = (qpy_rng_get() % 100000) / 2;
+    Helios_DataCall_GetInfo(1, 0, &info);
+    inet_ntop(AF_INET, &info.v4.addr.ip, ip4_addr_str, sizeof(ip4_addr_str));
+
+    snprintf(local_sdp, sizeof(local_sdp),
+                      "v=0\r\n"
+                      "o=microVoIP %u %u IN IP4 %s\r\n"
+                      "s=microVoIP 1.6.5\r\n"
+                      "c=IN IP4 %s\r\n"
+                      "t=0 0\r\n"
+                      "m=audio 19537 RTP/AVP 0 101\r\n"
+                      "a=rtpmap:0 PCMU/8000\r\n"
+                      "a=fmtp:101 0-15\r\n"
+                      "a=ptime:20\r\n"
+                      "a=maxptime:150\r\n"
+                      "a=sendrecv\r\n",
+                      random, (random + 2),
+                      ip4_addr_str, ip4_addr_str);
+
+    i += osip_message_set_body(sip, local_sdp, strlen(local_sdp));
+
+    i += osip_message_set_content_type(sip, "application/sdp");
+
+    return i;
+}
+
+int start_voip_service()
+{
+  int port = 5060;
+  char fromuser[32];
+  int automasquerade = 0;
+  const char *firewallip = NULL;
+  char proxy[256]; 
+  struct regparam_t regparam = {0, 3600, 0};
+  int err;
+  int pos = 0;
+
+  char prog_name[32];
+  int optval;
+  static int call_start = 0;
+  
+  snprintf(fromuser, sizeof(fromuser), "sip:%s@%s", voip->client.username, voip->client.password);
+  snprintf(prog_name, sizeof(prog_name), "%s (%s)", QUECPPYTHON_PROG_NAME, eXosip_get_version());
+  snprintf(proxy, sizeof(proxy), "sip:%s:%d", voip->client.serverip, voip->client.server_port);
+  regparam.expiry = voip->client.keepalive;
+
+  QPY_MODVOIP_LOG("%s up and running [testing on [%d] REGISTER [%s] Expires [%d] From: [%s]%s%s]\n", prog_name, voip->client.proto, proxy, regparam.expiry, fromuser,
+                                                                                                                                                                                                       voip->client.username, voip->client.password);
+
+  struct eXosip_t *context_eXosip = (struct eXosip_t  *)eXosip_malloc();
+  voip->context_eXosip = context_eXosip;
+
+  if (eXosip_init(context_eXosip)) {
+    QPY_MODVOIP_LOG("eXosip_init failed\n");
+    return -1;
+  }
+
+  err = -1;
+  switch(voip->client.proto) {
+       case HELIOS_VOIP_UDP:
+       err = eXosip_listen_addr(context_eXosip, IPPROTO_UDP, NULL, port, AF_INET, 0);
+               break;
+       case HELIOS_VOIP_TCP:
+       err = eXosip_listen_addr(context_eXosip, IPPROTO_TCP, NULL, port, AF_INET, 0);
+               break;
+       case HELIOS_VOIP_TLS:
+       err = eXosip_listen_addr(context_eXosip, IPPROTO_TCP, NULL, port, AF_INET, 1);
+               break;
+       case HELIOS_VOIP_DTLS:
+       err = eXosip_listen_addr(context_eXosip, IPPROTO_UDP, NULL, port, AF_INET, 1);
+               break;
+       default:
+               err = -1;
+               break;
+  }
+
+  if (err) {
+    QPY_MODVOIP_LOG("eXosip_listen_addr failed\n");
+    eXosip_quit(context_eXosip);
+    osip_free(context_eXosip);
+    return -1;
+  }
+
+  if (firewallip) {
+    QPY_MODVOIP_LOG("firewall address: %s:%i\n", firewallip, port);
+    eXosip_masquerade_contact(context_eXosip, firewallip, port);
+  }
+
+  optval = automasquerade;
+  eXosip_set_option(context_eXosip, EXOSIP_OPT_AUTO_MASQUERADE_CONTACT, &optval);
+
+  if (automasquerade) {
+    QPY_MODVOIP_LOG("automasquerade enabled\n");
+  }
+
+  eXosip_set_user_agent(context_eXosip, prog_name);
+
+  if (eXosip_add_authentication_info(context_eXosip, voip->client.username, voip->client.username, voip->client.password, NULL, NULL)) {
+      QPY_MODVOIP_LOG("eXosip_add_authentication_info failed\n");
+      eXosip_quit(context_eXosip);
+      osip_free(context_eXosip);
+      return -1;
+  }
+
+  {
+    osip_message_t *reg = NULL;
+    int i;
+
+    eXosip_lock(context_eXosip);
+    regparam.regid = eXosip_register_build_initial_register(context_eXosip, fromuser, proxy, NULL, regparam.expiry * 2, &reg);
+
+    if (regparam.regid < 1) {
+      eXosip_unlock(context_eXosip);
+      QPY_MODVOIP_LOG("eXosip_register_build_initial_register failed\n");
+      eXosip_quit(context_eXosip);
+      osip_free(context_eXosip);
+      return -1;
+    }
+
+    i = eXosip_register_send_register(context_eXosip, regparam.regid, reg);
+    eXosip_unlock(context_eXosip);
+
+    if (i != 0) {
+      QPY_MODVOIP_LOG("eXosip_register_send_register failed\n");
+      eXosip_quit(context_eXosip);
+      osip_free(context_eXosip);
+      return -1;
+    }
+  }
+
+  for (; keepRunning;) {
+    static int counter = 0;
+    eXosip_event_t *event;
+
+    counter++;
+
+
+    if (!(event = eXosip_event_wait(context_eXosip, 0, 1))) {
+#ifdef OSIP_MONOTHREAD
+      eXosip_execute(context_eXosip);
+#endif
+      eXosip_lock(context_eXosip);
+      eXosip_automatic_action(context_eXosip);
+      eXosip_unlock(context_eXosip);
+      osip_usleep(10000);
+      continue;
+    }
+
+#ifdef OSIP_MONOTHREAD
+    eXosip_execute(context_eXosip);
+#endif
+
+    eXosip_lock(context_eXosip);
+    eXosip_automatic_action(context_eXosip);
+
+    switch (event->type) {
+    case EXOSIP_REGISTRATION_SUCCESS:
+      QPY_MODVOIP_LOG("registrered successfully\n");
+      break;
+
+    case EXOSIP_REGISTRATION_FAILURE:
+      break;
+
+    case EXOSIP_CALL_INVITE: {
+               osip_message_t *answer;
+               int i;
+               voip->call_id = event->cid;
+               voip->dialog_id = event->did;
+               QPY_MODVOIP_LOG("Received a INVITE msg from %s:%s, UserName is %s, password is %s\n", event->request->req_uri->host,
+                                               event->request->req_uri->port, event->request->req_uri->username, event->request->req_uri->password);
+
+               
+               sdp_message_t *remote_sdp = eXosip_get_remote_sdp(context_eXosip, event->did);
+
+               i = eXosip_call_send_answer (context_eXosip, event->tid, 180, NULL);
+
+           i = eXosip_call_build_answer (context_eXosip, event->tid, 200, &answer);
+        
+           if (i != 0) {
+
+            eXosip_call_send_answer (context_eXosip, event->tid, 400, NULL);
+          
+           } else {
+               
+            i = sdp_complete_200ok(answer);
+                
+            if(i != 0) {
+                
+                eXosip_call_send_answer (context_eXosip, event->tid, 415, NULL);
+                QPY_MODVOIP_LOG("[ERROR]complete 200ok fail!\n");
+                
+            } else {
+
+                eXosip_call_send_answer (context_eXosip, event->tid, 200, answer);
+
+                sdp_media_t * audio_sdp = eXosip_get_audio_media(remote_sdp);
+
+                if (!audio_sdp) return false;
+                char* audio_port = audio_sdp->m_port; //audio_port
+                QPY_MODVOIP_LOG("audio_sdp port = %s\n", audio_port);
+                for (int i = 0; i < audio_sdp->a_attributes.nb_elt; i++)
+                {
+                       sdp_attribute_t *attr = (sdp_attribute_t*)osip_list_get(&audio_sdp->a_attributes, i);
+                       QPY_MODVOIP_LOG("%s : %s\n", attr->a_att_field, attr->a_att_value);
+                }
+                if( call_start == 0 ) {
+                       rtp_service_start(voip->client.serverip, atoi(audio_port), &(voip->media));
+                       call_start = 1;
+                }
+            }
+        }
+
+#if 0
+      osip_message_t *answer;
+      int i;
+
+      i = eXosip_call_build_answer(context_eXosip, event->tid, 405, &answer);
+      //i = eXosip_call_build_answer(context_eXosip, event->tid, 200, &answer);
+
+      if (i != 0) {
+        QPY_MODVOIP_LOG("failed to reject INVITE\n");
+        break;
+      }
+
+      osip_free(answer->reason_phrase);
+      answer->reason_phrase = osip_strdup("No Support for Incoming Calls");
+      i = eXosip_call_send_answer(context_eXosip, event->tid, 405, answer);
+      //i = eXosip_call_send_answer(context_eXosip, event->tid, 200, answer);
+
+      if (i != 0) {
+        QPY_MODVOIP_LOG("failed to reject INVITE\n");
+        break;
+      }
+
+      QPY_MODVOIP_LOG("INVITE rejected with 405\n");
+#endif
+         break;
+    }
+
+    case EXOSIP_MESSAGE_NEW: {
+      osip_message_t *answer;
+      int i;
+
+      //i = eXosip_message_build_answer(context_eXosip, event->tid, 405, &answer);
+
+      i = eXosip_message_build_answer (context_eXosip, event->tid, 200, &answer);
+
+      if (i != 0) {
+        QPY_MODVOIP_LOG("failed to reject %s\n", event->request->sip_method);
+        break;
+      }
+
+      //i = eXosip_message_send_answer(context_eXosip, event->tid, 405, answer);
+      i = eXosip_message_send_answer (context_eXosip, event->tid, 200, answer);
+
+      if (i != 0) {
+        QPY_MODVOIP_LOG("failed to reject %s\n", event->request->sip_method);
+        break;
+      }
+
+      QPY_MODVOIP_LOG("%s rejected with 405\n", event->request->sip_method);
+      break;
+    }
+
+    case EXOSIP_CALL_CLOSED:
+    case EXOSIP_CALL_RELEASED:
+    case EXOSIP_CALL_ACK:
+      break;
+
+    default:
+      QPY_MODVOIP_LOG("received unknown eXosip event (type, did, cid) = (%d, %d, %d)\n", event->type, event->did, event->cid);
+    }
+
+    eXosip_unlock(context_eXosip);
+    eXosip_event_free(event);
+  }
+
+  eXosip_quit(context_eXosip);
+  osip_free(context_eXosip);
+  return 0;
+}
+
+static void voip_main_task_entry(void * argv)
+{
+       (void)argv;
+       int ret = 0;
+       ret = start_voip_service();
+       QPY_MODVOIP_LOG("voip_app_task_entry ret %d\n", ret);
+}
+
+// server,sport,user,pwd,myip,pyport,transfer,keepalive,callback
+STATIC mp_obj_t voip_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) {
+    mp_arg_check_num(n_args, n_kw, 8, 9, false);
+    if (voip == NULL) {
+        voip = m_new_obj_with_finaliser(voip_obj_t);
+    } else {
+        mp_raise_ValueError(MP_ERROR_TEXT("ERR_VOIP_IS_BUSY"));
+    }
+    voip_obj_t* self = voip;
+    self->base.type = &mp_voip_type;
+
+       switch(n_args) {
+               case 9: {
+                       if (mp_sched_schedule_callback_register(&self->voip_event_callback, args[8]) != true) {
+                mp_raise_OSError(MP_EINVAL);
+            }
+               }
+               case 8: {
+                       self->client.keepalive = mp_obj_get_int(args[7]);
+               }
+               case 7: {
+                       self->client.proto = (Helios_Voip_transfer_proto_e)mp_obj_get_int(args[6]);
+               }
+               case 6: {
+                       self->client.local_port = mp_obj_get_int(args[5]);
+               }
+               case 5: {
+                       strcpy(self->client.localip, (char *)mp_obj_str_get_str(args[4]));
+               }
+               case 4: {
+                       strcpy(self->client.username, (char *)mp_obj_str_get_str(args[3]));
+               }
+               case 3: {
+                       strcpy(self->client.password, (char *)mp_obj_str_get_str(args[2]));
+               }
+               case 2: {
+                       self->client.server_port = mp_obj_get_int(args[1]);
+               }
+               case 1:
+                       strcpy(self->client.serverip, (char *)mp_obj_str_get_str(args[0]));
+                       break;
+               default:
+                       mp_raise_OSError(MP_EFAULT);
+                       break;
+       }
+
+       Helios_ThreadAttr ThreadAttr = {
+               .name = "voip_main_task",
+               .stack_size = 4096*2,
+               .priority = 100,
+               .entry = voip_main_task_entry,
+               .argv = NULL
+       };
+
+       self->voip_main_task = Helios_Thread_Create(&ThreadAttr);
+
+    return MP_OBJ_FROM_PTR(self);
+}
+
+//start call
+STATIC mp_obj_t qpy_voip_call(mp_obj_t self_in, mp_obj_t phone_num)
+{
+       voip_obj_t* self = MP_OBJ_TO_PTR(self_in);
+       mp_buffer_info_t phonenum = {0};
+       mp_get_buffer_raise(phone_num, &phonenum, MP_BUFFER_READ);
+
+       if (phonenum.len <= 0)
+       {
+               return mp_obj_new_int(-1);
+       }
+
+
+       return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_voip_call_obj, qpy_voip_call);
+
+//answer call
+STATIC mp_obj_t qpy_voip_answer(mp_obj_t self_in)
+{
+       voip_obj_t* self = MP_OBJ_TO_PTR(self_in);
+       return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_voip_answer_obj, qpy_voip_answer);
+
+//end call
+STATIC mp_obj_t qpy_voip_handup(mp_obj_t self_in)
+{
+       voip_obj_t* self = MP_OBJ_TO_PTR(self_in);
+       rtp_service_stop();
+       eXosip_lock(self->context_eXosip);
+       eXosip_call_terminate(self->context_eXosip, self->call_id, self->dialog_id);
+       eXosip_unlock(self->context_eXosip);
+       return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_voip_handup_obj, qpy_voip_handup);
+
+STATIC mp_obj_t qpy_voip_set_media(mp_obj_t self_in, mp_obj_t media_type, mp_obj_t media)
+{
+       voip_obj_t* self = MP_OBJ_TO_PTR(self_in);
+       self->media.type = (Helios_Voip_media_e)mp_obj_get_int(media_type);
+
+       if( self->media.type == HELIOS_VOIP_MEDIA_PCM ) {
+               machine_pcm_obj_t *pcm = MP_OBJ_TO_PTR(media);
+               self->media.pcm_handle_read = pcm->handle_read;
+               self->media.pcm_handle_write = pcm->handle_write;
+#if MICROPY_QPY_MODULE_G711
+       } else if( self->media.type == HELIOS_VOIP_MEDIA_PCM_G711_A || HELIOS_VOIP_MEDIA_PCM_G711_U ) {
+               G711_obj_t *pcm_G711 = MP_OBJ_TO_PTR(media);
+               self->media.pcm_handle_read = pcm_G711->pcm_handler.handle_read;
+               self->media.pcm_handle_write = pcm_G711->pcm_handler.handle_write;
+#endif
+       } else {
+               mp_raise_OSError(MP_EINVAL);
+       }
+
+       //rtp_media_init(&(self->media));
+
+       return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_voip_set_media_obj, qpy_voip_set_media);
+
+STATIC mp_obj_t qpy_module_voip_delete(mp_obj_t self_in)
+{
+       (void)self_in;
+       return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_module_voip_delete_obj, qpy_module_voip_delete);
+
+STATIC const mp_rom_map_elem_t voip_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_voip) },
+    { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&qpy_module_voip_delete_obj) },
+    { MP_ROM_QSTR(MP_QSTR_call), MP_ROM_PTR(&qpy_voip_call_obj) },
+    { MP_ROM_QSTR(MP_QSTR_answer), MP_ROM_PTR(&qpy_voip_answer_obj) },
+    { MP_ROM_QSTR(MP_QSTR_hangup), MP_ROM_PTR(&qpy_voip_handup_obj) },
+    { MP_ROM_QSTR(MP_QSTR_setMedia), MP_ROM_PTR(&qpy_voip_set_media_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_UDP), MP_ROM_INT(HELIOS_VOIP_UDP)},
+    { MP_ROM_QSTR(MP_QSTR_TCP), MP_ROM_INT(HELIOS_VOIP_TCP)},
+    { MP_ROM_QSTR(MP_QSTR_TLS), MP_ROM_INT(HELIOS_VOIP_TLS)},
+    { MP_ROM_QSTR(MP_QSTR_DTLS), MP_ROM_INT(HELIOS_VOIP_DTLS)},
+    
+       { MP_ROM_QSTR(MP_QSTR_MEDIA_PCM), MP_ROM_INT(HELIOS_VOIP_MEDIA_PCM)},
+    { MP_ROM_QSTR(MP_QSTR_MEDIA_PCM_G711_A), MP_ROM_INT(HELIOS_VOIP_MEDIA_PCM_G711_A)},
+    { MP_ROM_QSTR(MP_QSTR_MEDIA_PCM_G711_U), MP_ROM_INT(HELIOS_VOIP_MEDIA_PCM_G711_U)},
+    { MP_ROM_QSTR(MP_QSTR_MEDIA_PCM_G729), MP_ROM_INT(HELIOS_VOIP_MEDIA_PCM_G729)},
+};
+STATIC MP_DEFINE_CONST_DICT(voip_locals_dict, voip_locals_dict_table);
+
+const mp_obj_type_t mp_voip_type = {
+    .base = { &mp_type_type },
+    .name = MP_QSTR_voip,
+    .make_new = voip_make_new,
+    .locals_dict = (mp_obj_dict_t *)&voip_locals_dict,
+};
+
+#endif
+
+
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modwifi.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modwifi.c
new file mode 100644 (file)
index 0000000..8750f7e
--- /dev/null
@@ -0,0 +1,990 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpconfigport.h"
+#include "runtime.h"
+
+#if MICROPY_QPY_MODULE_WIFI
+#include "modwifi.h"
+
+#define QPY_WIFI_LOG(msg, ...)      custom_log(modwifi, msg, ##__VA_ARGS__)
+
+static uint power_ctrl = 0;
+static uint sleep_ctrl = 0;
+int wifi_flag = -1;
+wifi_obj_t *wifi;
+c_callback_t * g_usrwifi_callback = NULL;
+static Helios_Thread_t wifi_threadid = 0;
+static Helios_Sem_t wifi_Sema;
+
+#if MICROPY_QPY_MODULE_WIFI_RINGBUFF
+Helios_wifi_ring_buf_t *Helios_wifi_ring_buf_socket[4] = {NULL, NULL, NULL, NULL};
+Helios_Mutex_t Helios_wifi_read_mutex = 0;
+#endif
+
+#define WIFI_PACKET_LENGTH  3*1024
+enum parse_status {
+    SSS_NULL_DATA = 0,
+    SSS_RESPONSE_DATA,
+    SSS_IPD_DATA,
+    SSS_REMAIN_DATA,
+};
+
+struct wifi_ipd_t {
+       int sockid;
+       int len;
+};
+struct wifi_at_parser_t {
+       enum parse_status status;
+       struct wifi_ipd_t ipd;
+       int is_ipd_exist;
+    int data_len;
+       char data[WIFI_PACKET_LENGTH];
+       char remain_data[WIFI_PACKET_LENGTH];
+};
+
+struct wifi_ipd_queue_t {
+       int length;
+       char *data;
+};
+
+struct wifi_at_parser_t wifi_at_parser;
+
+extern void resolve_response_data(char *recv_buff);
+extern void resolve_ipd_data(int sockid, char *ipd_data, int len);
+extern void at_parse(char * readdata, int readsize, char *at_response);
+
+
+void uart_callback(uint64_t ind_type, Helios_UARTNum port, uint64_t size)
+{
+    Helios_Semaphore_Release(wifi_Sema);
+}
+
+int wifi_wait_at_ok(int uart_num, char * atcmd)
+{
+    int ret = 0, timeout = 0;
+    int ap_touch_start = 0;
+       char at_response[512] = {0};
+
+    while (1)
+    {
+        ret =  Helios_UART_Any((Helios_UARTNum) uart_num);
+
+        if (ret == 0)
+        {
+            timeout++;
+            if ((!strncmp((const char * )atcmd, "AT+CIPSTART=", 12)) || (!strncmp((const char * )atcmd, "AT+CIPDOMAIN=", 13)))
+            {
+                Helios_msleep(100);
+
+                if (timeout > 200)
+                {
+                    if (wifi->recvlen > 0)
+                    {
+                        return 1;
+                    }
+                    return -3;
+                }
+            }
+            else if (!strncmp((const char * )atcmd, "AT+CWJAP=", 9))
+            {
+                Helios_msleep(100);
+                if (timeout > 20)
+                {
+                    return -3;
+                }
+            }
+            else if (!strncmp((const char * )atcmd, "ATE0", 4))
+            {
+                Helios_msleep(50);
+                if (timeout > 20)
+                {
+                    return -3;
+                }
+            }
+            else if (!strncmp((const char * )atcmd, "AT", 2))
+            {
+                Helios_msleep(50);
+                if (timeout > 100)
+                {
+                    return -3;
+                }
+            }
+            else
+            {
+                Helios_msleep(500);
+                if (timeout > 400)
+                {
+                    return -3;
+                }
+
+            }
+        }
+        else if ( ret > 0)
+        {
+            char *recv_buff = NULL;
+            int read_len = 0;
+            char *data = NULL;
+            char *ipd_data = NULL;
+            char cmd[64] = {};
+
+            recv_buff = (char *)malloc(ret+1);
+            memset(recv_buff, 0, ret+1);
+            memset(wifi->recvdata, 0, sizeof(wifi->recvdata));
+
+            read_len = Helios_UART_Read((Helios_UARTNum) uart_num, recv_buff, ret);
+                       
+                       at_parse(recv_buff, read_len, at_response);
+                       if( wifi_at_parser.is_ipd_exist ) {
+                               strcpy(recv_buff, at_response);
+                       }
+
+            if (strstr((const char *)recv_buff, "SEND OK"))
+            {
+                //mp_printf(&mp_plat_print, "wifi_wait_at_ok SEND OK \r\n");
+                free(recv_buff);
+                recv_buff = NULL;
+                return 2;
+            }
+
+            data = strstr((const char *)recv_buff, "OK");
+            if ((!data) && (!ap_touch_start))
+            {
+                if (!strncmp((const char * )atcmd, "AT+CWJAP=", 9))
+                {
+                    data = strstr((const char *)recv_buff, "ERROR");
+                    if (data)
+                    {
+                        //mp_printf(&mp_plat_print, "wifi_wait_at_ok not ERROR \r\n");
+                        free(recv_buff);
+                        recv_buff = NULL;
+                        return -1;
+                    }
+                    else
+                    {
+                        //mp_printf(&mp_plat_print, "wifi_wait_at_ok continue \r\n");
+                        continue;
+                    }
+                }
+                else
+                {
+                    //mp_printf(&mp_plat_print, "wifi_wait_at_ok not OK \r\n");
+                    free(recv_buff);
+                    recv_buff = NULL;
+                    return -1;
+                }
+            }
+
+#if 0
+            if (!strcmp((const char * )atcmd, "AT+AP_TOUCH_START\r\n"))
+            {
+                mp_printf(&mp_plat_print, "wifi_wait_at_ok ap_touch_start %d \r\n", ap_touch_start);
+                if (!ap_touch_start)
+                {
+                    ap_touch_start = 1;
+                    wifi->recvlen = 0;
+                    memset(wifi->recvdata, 0, sizeof(wifi->recvdata));
+                    continue;
+                }
+
+                data = strstr((const char *)recv_buff, "aptouch connected wifi");
+                wifi->recvlen += read_len-2;
+                if (data)
+                {
+                    memset(wifi->recvdata, 0, sizeof(wifi->recvdata));
+                    mp_printf(&mp_plat_print, "wifi_wait_at_ok return data= %s  \r\n");
+                    strncpy(wifi->recvdata, data, 22);
+                    mp_printf(&mp_plat_print, "wifi_wait_at_ok return 1 \r\n");
+                    return 1;
+                }
+                else
+                {
+                    //strncpy(wifi->recvdata, recv_buff, wifi->recvlen);
+                    if (g_usrwifi_callback != NULL)
+                    {
+                        GC_STACKTOP_SET();
+                        mp_sched_schedule_ex(g_usrwifi_callback, mp_obj_new_str(recv_buff, read_len));
+                        GC_STACKTOP_CLEAR();
+                    }
+                    continue;
+                }
+            }
+#endif
+
+            strncpy(cmd, atcmd, strlen((const char *)atcmd)-2);
+            //mp_printf(&mp_plat_print, "wifi_wait_at_ok cmd <<<%s>>>len(%d) \r\n", cmd, strlen((const char *)cmd));
+
+            /**??AT  ??**/
+            if ((!strcmp((const char * )cmd, "AT+RST")) || (!strcmp((const char * )cmd, "AT"))
+                 || (!strcmp((const char * )cmd, "ATE0")) || (!strncmp((const char * )cmd, "AT+GSLP=", 8)) 
+                 || (!strcmp((const char * )cmd, "AT+RESTORE")) || (!strncmp((const char * )cmd, "AT+SLEEP=", 9))
+                 || (!strncmp((const char * )cmd, "AT+UART_CUR=", 12)) || (!strncmp((const char * )cmd, "AT+UART_DEF=", 12))
+                 || (!strncmp((const char * )cmd, "AT+SYSMSG=", 10)) || (!strncmp((const char * )cmd, "AT+USERRAM=", 11))
+                 || (!strncmp((const char * )cmd, "AT+FS=", 6)) || (!strncmp((const char * )cmd, "AT+RFPOWER=", 11))
+                 || (!strcmp((const char * )cmd, "AT+SYSROLLBACK")) || (!strncmp((const char * )cmd, "AT+SYSTIMESTAMP=", 16))
+                 || (!strncmp((const char * )cmd, "AT+SYSLOG=", 10)) || (!strncmp((const char * )cmd, "AT+SLEEPWKCFG=", 14))
+                 || (!strncmp((const char * )cmd, "AT+SYSSTORE=", 12))
+                )
+            {
+                free(recv_buff);
+                recv_buff = NULL;
+                return 0;
+            }
+            else if ((!strcmp((const char * )cmd, "AT+GMR")) || (!strcmp((const char * )cmd, "AT+CMD?"))
+                    || (!strcmp((const char * )cmd, "AT+UART_CUR?")) || (!strcmp((const char * )cmd, "AT+UART_DEF?"))
+                    || (!strcmp((const char * )cmd, "AT+SLEEP?")) || (!strcmp((const char * )cmd, "AT+SYSRAM?"))
+                    || (!strcmp((const char * )cmd, "AT+SYSMSG?")) || (!strcmp((const char * )cmd, "AT+USERRAM?"))
+                    || (!strcmp((const char * )cmd, "AT+SYSFLASH?")) || (!strncmp((const char * )cmd, "AT+SYSFLASH=", 12))
+                    || (!strcmp((const char * )cmd, "AT+RFPOWER?")) || (!strcmp((const char * )cmd, "AT+SYSTIMESTAMP?"))
+                    || (!strcmp((const char * )cmd, "AT+SYSLOG?")) || (!strcmp((const char * )cmd, "AT+SYSSTORE?"))
+                    || (!strncmp((const char * )cmd, "AT+SYSREG=", 10)) || (!strcmp((const char * )cmd, "AT+SYSTEMP?"))
+            )
+            {
+                wifi->recvlen = (read_len - 4);
+                strncpy(wifi->recvdata, recv_buff, wifi->recvlen);
+                free(recv_buff);
+                recv_buff = NULL;
+                return 1;
+            }
+            else if ((!strncmp((const char * )cmd, "AT+CWMODE=", 10)) || (!strncmp((const char * )cmd, "AT+CWRECONNCFG=", 15))
+                  || (!strncmp((const char * )cmd, "AT+CWLAPOPT=", 12)) || (!strcmp((const char * )cmd, "AT+CWQAP"))
+                  || (!strcmp((const char * )cmd, "AT+CWQIF")) || (!strncmp((const char * )cmd, "AT+CWQIF=", 9))
+                  || (!strncmp((const char * )cmd, "AT+CWDHCP=", 10)) || (!strncmp((const char * )cmd, "AT+CWAUTOCONN=", 14))
+                  || (!strncmp((const char * )cmd, "AT+CWAPPROTO=", 13)) || (!strncmp((const char * )cmd, "AT+CWSTAPROTO=", 14))
+                  || (!strncmp((const char * )cmd, "AT+CIPSTAMAC=", 13)) || (!strncmp((const char * )cmd, "AT+CIPAPMAC=", 12))
+                  || (!strncmp((const char * )cmd, "AT+CIPSTA=", 10)) || (!strncmp((const char * )cmd, "AT+CIPAP=", 9))
+                  || (!strncmp((const char * )cmd, "AT+WPS=", 7)) || (!strncmp((const char * )cmd, "AT+MDNS=", 7))
+                  || (!strncmp((const char * )cmd, "AT+CWHOSTNAME=", 14)) || (!strncmp((const char * )cmd, "AT+CWCOUNTRY=", 13))
+                )/** Wi-Fi AT???**/
+            {
+                free(recv_buff);
+                recv_buff = NULL;
+                return 0;
+            }
+            else if ((!strcmp((const char * )cmd, "AT+CWMODE?")) || (!strcmp((const char * )cmd, "AT+CWJAP?"))
+                      || (!strcmp((const char * )cmd, "AT+CWRECONNCFG?")) || (!strcmp((const char * )cmd, "AT+CWLAP"))
+                      || (!strcmp((const char * )cmd, "AT+CWSAP?")) || (!strcmp((const char * )cmd, "AT+CWLIF"))
+                      || (!strcmp((const char * )cmd, "AT+CWDHCP?")) || (!strcmp((const char * )cmd, "AT+CWDHCPS?"))
+                      || (!strcmp((const char * )cmd, "AT+CWAPPROTO?")) || (!strcmp((const char * )cmd, "AT+CWSTAPROTO?"))
+                      || (!strcmp((const char * )cmd, "AT+CIPSTAMAC?")) || (!strcmp((const char * )cmd, "AT+CIPAPMAC?"))
+                      || (!strcmp((const char * )cmd, "AT+CIPSTA?")) || (!strcmp((const char * )cmd, "AT+CIPAP?"))
+                      || (!strcmp((const char * )cmd, "AT+CWHOSTNAME?")) || (!strcmp((const char * )cmd, "AT+CWCOUNTRY?"))
+                    )
+            {
+                wifi->recvlen = (read_len - 4);
+                strncpy(wifi->recvdata, recv_buff, wifi->recvlen);
+                free(recv_buff);
+                recv_buff = NULL;
+                return 1;
+            }
+            else if ((!strcmp((const char * )cmd, "AT+CWJAP"))
+                      || (!strncmp((const char * )cmd, "AT+CWLAP=", 9))
+                    )
+            {
+                wifi->recvlen = read_len;
+                strncpy(wifi->recvdata, recv_buff, wifi->recvlen);
+                free(recv_buff);
+                recv_buff = NULL;
+                return 1;
+            }
+            /** TCP/IP AT???**/
+            else if ((!strncmp((const char * )cmd, "AT+CIPDOMAIN=", 13)) || (!strcmp((const char * )cmd, "AT+CIPMUX?"))
+                    ||(!strncmp((const char * )cmd, "AT+CIPSTART=", 12)) || (!strncmp((const char * )cmd, "AT+CIPCLOSE=", 12))
+                    || (!strncmp((const char * )cmd, "AT+CIPSTATUS", 12))
+            )
+            {
+                //mp_printf(&mp_plat_print, "wifi_wait_at_ok read_len(%d) \r\n", read_len);
+                wifi->recvlen = read_len;
+                strncpy(wifi->recvdata, recv_buff, wifi->recvlen);
+                free(recv_buff);
+                recv_buff = NULL;
+                return 1;
+            }
+            else if ((!strncmp((const char * )cmd, "AT+CIPMUX=", 10)) || (!strncmp((const char * )cmd, "AT+CIPSEND=", 11))
+                    ||(!strncmp((const char * )cmd, "AT+CWJAP=", 9))
+            )
+            {
+                free(recv_buff);
+                recv_buff = NULL;
+                return 0;
+            }
+            else
+            {
+                free(recv_buff);
+                recv_buff = NULL;
+                return -2;
+            }
+
+        }
+    }
+}
+
+
+static int get_ipd_head(char *buffer, int src_len, struct wifi_at_parser_t *wifi_parser)
+{
+       int index = -1;
+       char *ptr = buffer;
+       int ret = 0;
+    int sockid;
+    int dst_len;
+
+    ret = sscanf(ptr, "%*[^,],%d,%d:[^:]", &sockid, &dst_len);
+    if( ret != 2 ) {
+        return -1;
+    }
+    wifi_parser->ipd.sockid = sockid;
+    wifi_parser->ipd.len = dst_len;
+
+       for(index = 4; index < src_len; index++ ) {
+               if( buffer[index] == ':' ) break;
+       }
+       
+       return (index+1);
+}
+
+static int check_wifi_at_data(struct wifi_at_parser_t *wifi_parser, char * readdata, int readsize)
+{
+    int i = 0;
+    int index = 0;
+    if( readsize <= 0 || readdata == NULL ) return 0;
+    for(i = 0; i < readsize; i++ ) {
+        if( readdata[i] == '+' ) {
+            if( readsize > 3 ) {
+                if( !strncmp(&readdata[i], "+IPD", 4) ) {
+                    if( i != 0 ) {
+                        strncpy(wifi_parser->data, readdata, i);
+                        wifi_parser->data_len = i;
+                        wifi_parser->status = SSS_RESPONSE_DATA;
+                        return i;
+                    }
+                    index = get_ipd_head(&readdata[i], readsize - i, wifi_parser);
+                    if( (index > 0) && (wifi_parser->ipd.len <= (readsize - index)) ) {
+                        memcpy(wifi_parser->data, &readdata[index], wifi_parser->ipd.len);
+                        wifi_parser->status = SSS_IPD_DATA;
+                        return (index + wifi_parser->ipd.len);
+                    } else {
+                        memcpy(wifi_parser->data, readdata, readsize);
+                        wifi_parser->data_len = readsize;
+                        wifi_parser->status = SSS_REMAIN_DATA;
+                        return readsize;
+                    }
+                }
+            } else {
+                memcpy(wifi_parser->data, readdata, readsize);
+                wifi_parser->data_len = readsize;
+                wifi_parser->status = SSS_REMAIN_DATA;
+                return readsize;
+            }
+        }
+    }
+    strncpy(wifi_parser->data, readdata, readsize);
+    wifi_parser->data_len = readsize;
+    wifi_parser->status = SSS_RESPONSE_DATA;
+    return readsize;
+}
+
+static int clear_remain_msg(struct wifi_at_parser_t *wifi_parser, char * readdata, int readsize)
+{
+    int offset = 0;
+       
+    offset = WIFI_PACKET_LENGTH - wifi_parser->data_len;
+    if( readsize <  offset ) {
+        offset = readsize;
+    }
+    memcpy(wifi_parser->remain_data, wifi_parser->data, wifi_parser->data_len);
+    memcpy(&wifi_parser->remain_data[wifi_parser->data_len], readdata, offset);
+    offset = check_wifi_at_data(wifi_parser, wifi_parser->remain_data, wifi_parser->data_len+offset);
+    return (offset - wifi_parser->data_len);
+}
+
+void at_parse(char * readdata, int readsize, char *at_response)
+{
+    struct wifi_at_parser_t *wifi_parser = &wifi_at_parser;
+       wifi_parser->is_ipd_exist = 0;
+    int eaten = 0;
+    int remain_length = readsize;
+
+    if( wifi_parser->status == SSS_REMAIN_DATA ) {
+        eaten = clear_remain_msg(wifi_parser, readdata, readsize);
+               resolve_ipd_data(wifi_parser->ipd.sockid, wifi_parser->data, wifi_parser->ipd.len);
+    }
+
+    do {
+        remain_length = readsize - eaten;
+        eaten += check_wifi_at_data(wifi_parser, &readdata[eaten], remain_length);
+        switch (wifi_parser->status) {
+            case SSS_REMAIN_DATA:
+            case SSS_NULL_DATA:
+                return;
+            case SSS_IPD_DATA:
+                               resolve_ipd_data(wifi_parser->ipd.sockid, wifi_parser->data, wifi_parser->ipd.len);
+                wifi_parser->status = SSS_NULL_DATA;
+                wifi_parser->data_len = 0;
+                               wifi_parser->is_ipd_exist += 1;
+                break;
+            case SSS_RESPONSE_DATA:
+                               if( wifi_parser->data_len > 4 ) {
+                                       if( at_response != NULL ) {
+                                               strncpy(at_response, wifi_parser->data, wifi_parser->data_len);
+                                       }
+                               }
+                               resolve_response_data(wifi_parser->data);
+                wifi_parser->status = SSS_NULL_DATA;
+                wifi_parser->data_len = 0;
+                break;
+            default:
+                return;
+        }
+    } while(remain_length);
+}
+
+void resolve_ipd_data(int sockid, char *ipd_data, int len)
+{
+       int ret = 0;
+       int retry = 100;
+
+       char flag = 0x01;
+       if( sockid < 0 || sockid > 3)
+    {
+        mp_printf(&mp_plat_print, "[wifi_read] socket Fail sockid  = %d\r\n", sockid);
+               return;
+    }
+
+       do {
+       ret = Helios_wifi_rb_write(Helios_wifi_ring_buf_socket[sockid], (unsigned char *)(ipd_data), len);
+       if (ret > 0) {
+               //mp_printf(&mp_plat_print, "[wifi_read] data_ind release msg, %d,%d\r\n", sockid, wifi->data_ind[sockid]);
+                       Helios_MsgQ_Put(wifi->data_ind[sockid], &flag, sizeof(char), HELIOS_NO_WAIT);
+                       return;
+               }
+               Helios_msleep(10);
+       } while(retry--);
+       mp_printf(&mp_plat_print, "[wifi_read] wifi_ipd_data ret FAIL\r\n");
+}
+
+void resolve_response_data(char *recv_buff)
+{
+               char *data = NULL;
+               if (recv_buff)
+               {
+                       data = strstr((const char *)recv_buff, ",CLOSED");
+                       if (data)
+                       {
+                               int sta = data[-1];
+                               if( sta < 0 || sta > 3) return;
+                               mp_printf(&mp_plat_print, "[wifi_read] recv socketid = %d closed\r\n", sta);
+#if 1          
+                               if( Helios_wifi_ring_buf_socket[sta] ) {
+                                       Helios_wifi_ring_buf_socket[sta]->peer_closed = 1;
+                               }
+#endif
+                       }
+       
+                       data = strstr((const char *)recv_buff, "WIFI CONNECTED");
+                       if (data)
+                       {
+                               mp_printf(&mp_plat_print, "wifi_wait_at_ok strstr WIFI CONNECTED\r\n");
+                               if (g_usrwifi_callback != NULL)
+                               {
+                                       GC_STACKTOP_SET();
+                                       mp_sched_schedule_ex(g_usrwifi_callback, mp_obj_new_str(data, 30));
+                                       GC_STACKTOP_CLEAR();
+                               }
+                       }
+               
+                       data = strstr((const char *)recv_buff, "WIFI GOT IP");
+                       if (data)
+                       {
+                               mp_printf(&mp_plat_print, "wifi_wait_at_ok strstr WIFI GOT IP \r\n");
+                               if (g_usrwifi_callback != NULL)
+                               {
+                                       GC_STACKTOP_SET();
+                                       mp_sched_schedule_ex(g_usrwifi_callback, mp_obj_new_str(data, 30));
+                                       GC_STACKTOP_CLEAR();
+                               }
+                       }
+                       
+                       data = strstr((const char *)recv_buff, "WIFI DISCONNECT");
+                       if (data)
+                       {
+                               mp_printf(&mp_plat_print, "wifi_wait_at_ok strstr WIFI DISCONNECT \r\n");
+                               if (g_usrwifi_callback != NULL)
+                               {
+                                       GC_STACKTOP_SET();
+                                       mp_sched_schedule_ex(g_usrwifi_callback, mp_obj_new_str(data, 30));
+                                       GC_STACKTOP_CLEAR();
+                               }
+                       }
+               
+                       data = strstr((const char *)recv_buff, "aptouch connected");
+                       if (data)
+                       {
+                               mp_printf(&mp_plat_print, "wifi_wait_at_ok strstr aptouch \r\n");
+                               if (g_usrwifi_callback != NULL)
+                               {
+                                       GC_STACKTOP_SET();
+                                       mp_sched_schedule_ex(g_usrwifi_callback, mp_obj_new_str(data, 100));
+                                       GC_STACKTOP_CLEAR();
+                               }
+                       }
+               
+                       data = strstr((const char *)recv_buff, "FAIL\r\n");
+                       if (data)
+                       {
+                               mp_printf(&mp_plat_print, "wifi_wait_at_ok FAIL  \r\n");
+                               if (g_usrwifi_callback != NULL)
+                               {
+                                       GC_STACKTOP_SET();
+                                       mp_sched_schedule_ex(g_usrwifi_callback, mp_obj_new_str(data, 100));
+                                       GC_STACKTOP_CLEAR();
+                               }
+                       }
+               }
+}
+
+static void wifi_isr_handler(void)
+{
+       int tmp_ret = 0;
+    int ret = Helios_Mutex_Lock(wifi->mutex, HELIOS_NO_WAIT);
+    if(ret != 0)
+    {
+        return;
+    }
+
+    ret =  Helios_UART_Any((Helios_UARTNum) wifi->uart_num);
+    //QPY_WIFI_LOG("wifi_isr_handler 22 <<< ret =%d>>>\r\n", ret);
+
+    if (ret)
+    {
+        int read_len = 0;
+        char *recv_buff = NULL;
+        recv_buff = (char *)malloc(ret);
+        memset(recv_buff, 0, ret);
+        memset(wifi->recvdata, 0, sizeof(wifi->recvdata));
+
+               read_len = Helios_UART_Read((Helios_UARTNum) wifi->uart_num, recv_buff, ret);
+
+               at_parse((char *)recv_buff, read_len, NULL);
+
+               free(recv_buff);
+               recv_buff = NULL;
+               //Helios_Mutex_Unlock(Helios_wifi_read_mutex);
+       }
+
+    Helios_Mutex_Unlock(wifi->mutex);
+}
+
+static void wifi_task_entry()
+{
+    while (1)
+    {
+        Helios_Semaphore_Acquire(wifi_Sema, HELIOS_WAIT_FOREVER);
+        wifi_isr_handler();
+    }
+}
+
+STATIC mp_obj_t set_wifi_init(size_t n_args, const mp_obj_t *args)
+{
+    int ret = 0;
+    wifi = (wifi_obj_t *)malloc(sizeof(wifi_obj_t));
+    memset(wifi, 0, sizeof(wifi_obj_t));
+    mp_int_t uart_num = mp_obj_get_int(args[0]);
+
+    if (uart_num < HELIOS_UART0 || uart_num > HELIOS_UARTMAX) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) does not exist"), uart_num);
+    }
+
+    wifi->uart_num = uart_num;
+    wifi->config.baudrate = HELIOS_UART_BAUD_115200;
+    wifi->config.data_bit = HELIOS_UART_DATABIT_8;
+    wifi->config.stop_bit = HELIOS_UART_STOP_1;
+    wifi->config.parity_bit = HELIOS_UART_PARITY_NONE;
+    wifi->config.flow_ctrl = HELIOS_UART_FC_NONE;
+
+    Helios_UARTInitStruct uart_para = {0};
+    Helios_UARTConfig uart_config = {0};
+    uart_para.uart_config = &uart_config;
+
+    memcpy((void*)&uart_config,(void*)&wifi->config, sizeof(Helios_UARTConfig));
+
+    Helios_UART_Deinit((Helios_UARTNum) uart_num);
+    
+    if(Helios_UART_Init((Helios_UARTNum) uart_num, &uart_para) != 0) {
+        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) init fail"), uart_num);
+    }
+
+    /*??wifi?????? 1:?? 0:??*/
+    power_ctrl = mp_obj_get_int(args[1]);
+
+    Helios_GPIOInitStruct gpio_struct = {0};
+    gpio_struct.dir = HELIOS_GPIO_OUTPUT;
+    gpio_struct.pull = HELIOS_PULL_UP;
+    gpio_struct.value = HELIOS_LVL_HIGH;
+    Helios_GPIO_Init((Helios_GPIONum) power_ctrl, &gpio_struct);
+
+    Helios_GPIO_SetLevel((Helios_GPIONum) power_ctrl, (Helios_LvlMode) 0);
+    Helios_GPIO_SetLevel((Helios_GPIONum) power_ctrl, (Helios_LvlMode) 1);
+    Helios_msleep(50);
+
+    /*??wifi???? 1:?? 0:??*/
+    sleep_ctrl = mp_obj_get_int(args[2]);
+    gpio_struct.dir = HELIOS_GPIO_OUTPUT;
+    gpio_struct.pull = HELIOS_PULL_UP;
+    gpio_struct.value = HELIOS_LVL_LOW;
+    Helios_GPIO_Init((Helios_GPIONum) sleep_ctrl, &gpio_struct);
+    Helios_GPIO_SetLevel((Helios_GPIONum) sleep_ctrl, (Helios_LvlMode) 1);
+    Helios_GPIO_SetLevel((Helios_GPIONum) sleep_ctrl, (Helios_LvlMode) 0);
+    Helios_msleep(50);
+
+    if (wifi->mutex == 0)
+    {
+        wifi->mutex = Helios_Mutex_Create();
+        if (wifi->mutex == 0)
+        {
+            Helios_UART_Deinit((Helios_UARTNum)wifi->uart_num);
+            mp_raise_ValueError(MP_ERROR_TEXT("create mutex failed."));
+        }
+    }
+       
+       for (int i = 0; i < 4; i++) {
+               if (wifi->data_ind[i] == 0)
+       {
+               wifi->data_ind[i] = Helios_MsgQ_Create(128, 1);
+               if (wifi->data_ind[i] == 0)
+               {
+               Helios_UART_Deinit((Helios_UARTNum)wifi->uart_num);
+               Helios_Mutex_Delete(wifi->mutex);
+               mp_raise_ValueError(MP_ERROR_TEXT("create ipd data queue failed."));
+               }
+       }
+       }
+
+    if (Helios_wifi_read_mutex == 0)
+    {
+        Helios_wifi_read_mutex = Helios_Mutex_Create();
+        if (Helios_wifi_read_mutex == 0)
+        {
+            Helios_UART_Deinit((Helios_UARTNum)wifi->uart_num);
+            Helios_Mutex_Delete(wifi->mutex);
+            mp_raise_ValueError(MP_ERROR_TEXT("create read mutex failed."));
+        }
+    }
+
+    if (wifi_Sema == 0)
+    {
+        wifi_Sema = Helios_Semaphore_Create(1, 0);;
+        if (wifi_Sema == 0)
+        {
+            Helios_UART_Deinit((Helios_UARTNum)wifi->uart_num);
+            Helios_Mutex_Delete(wifi->mutex);
+            Helios_Mutex_Delete(Helios_wifi_read_mutex);
+            mp_raise_ValueError(MP_ERROR_TEXT("create mutex failed."));
+        }
+    }
+
+    if (wifi_threadid == 0)
+    {
+        Helios_ThreadAttr ThreadAttr = {
+            .name = "wifi_task",
+            .stack_size = 8*1024,
+            .priority = 100,
+            .entry = wifi_task_entry,
+            .argv = NULL
+        };
+
+        wifi_threadid = Helios_Thread_Create(&ThreadAttr);
+        if(wifi_threadid == 0)
+        {
+            Helios_UART_Deinit((Helios_UARTNum)wifi->uart_num);
+            Helios_Mutex_Delete(wifi->mutex);
+            Helios_Mutex_Delete(Helios_wifi_read_mutex);
+            Helios_Semaphore_Delete(wifi_Sema);
+            mp_raise_ValueError(MP_ERROR_TEXT("create Thread failed."));
+        }
+    }
+
+    for (int i = 4; i > 0; i--)
+    {
+        char *cmd = "ATE0\r\n";
+        char *data = NULL;
+
+        Helios_UART_Write(uart_num, cmd, strlen((const char *)cmd));
+
+        ret = wifi_wait_at_ok(uart_num, cmd);
+        if (!ret)
+        {
+            QPY_WIFI_LOG("wifi_wait_at_ok ret = %d\r\n", ret);
+            break;
+        }
+    }
+
+    Helios_UART_SetCallback(uart_num, uart_callback);
+    wifi_flag = ret;
+
+    Helios_msleep(50);
+    _wifi_send_atcmd("AT+UART_CUR=115200,8,1,0,2\r\n", sizeof("AT+UART_CUR=115200,8,1,0,2\r\n"));
+    Helios_msleep(50);
+    _wifi_send_atcmd("AT+CWRECONNCFG=1,1000\r\n", sizeof("AT+CWRECONNCFG=1,1000\r\n"));
+    Helios_msleep(50);
+    _wifi_send_atcmd("AT+SLEEPAPKEEP=1\r\n", sizeof("AT+SLEEPAPKEEP=1\r\n"));
+
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qpy_setwifi_obj, 1, 10, set_wifi_init);
+
+int _wifi_send_atcmd(char * atcmd, int size)
+{
+    int ret = 0;
+
+    Helios_UART_Write(wifi->uart_num, (char *)atcmd, size);
+    Helios_msleep(50);
+    if (strcmp((const char * )atcmd, "AT+AP_TOUCH_START\r\n"))
+    {
+        MP_THREAD_GIL_EXIT();
+        ret = wifi_wait_at_ok(wifi->uart_num, (char *)atcmd);
+        MP_THREAD_GIL_ENTER();
+    }
+    return ret;
+}
+
+STATIC mp_obj_t wifi_send_atcmd(size_t n_args, const mp_obj_t *args)
+{
+    const char *atcmd = mp_obj_str_get_str(args[0]);
+
+    MP_THREAD_GIL_EXIT();
+    Helios_Mutex_Lock(wifi->mutex, HELIOS_WAIT_FOREVER);
+    MP_THREAD_GIL_ENTER();
+
+    int ret =  _wifi_send_atcmd((char *)atcmd, strlen(atcmd));
+    Helios_Mutex_Unlock(wifi->mutex);
+
+    QPY_WIFI_LOG("wifi_wait_at_ok ret = %d \r\n", ret);
+
+    if (ret == 1)
+    {
+        return mp_obj_new_str(wifi->recvdata, wifi->recvlen);
+    }
+    else
+    {
+        return mp_obj_new_int(ret);
+    }
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qpy_sendatcmd_obj, 1, 10, wifi_send_atcmd);
+
+STATIC mp_obj_t qpy_wifi_usr_callback(mp_obj_t callback)
+{
+    static c_callback_t cb = {0};
+    memset(&cb, 0, sizeof(c_callback_t));
+    g_usrwifi_callback = &cb;
+    mp_sched_schedule_callback_register(g_usrwifi_callback, callback);
+
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_register_usr_callback_obj, qpy_wifi_usr_callback);
+
+STATIC mp_obj_t qpy_wifi_set_flag(mp_obj_t flag)
+{
+    const int flag_w = mp_obj_get_int(flag);
+
+    if (flag_w == 1)
+    {
+        wifi_flag = 0;
+    }
+    else
+    {
+        wifi_flag = -1;
+    }
+
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_setwififlag_obj, qpy_wifi_set_flag);
+
+STATIC mp_obj_t wifi_stop(size_t n_args, const mp_obj_t *args)
+{
+    g_usrwifi_callback = NULL;
+
+    Helios_UART_Deinit(wifi->uart_num);
+
+    if (wifi->mutex != 0)
+    {
+        Helios_Mutex_Delete(wifi->mutex);
+        wifi->mutex = 0;
+    }
+
+    if (Helios_wifi_read_mutex != 0)
+    {
+        Helios_Mutex_Delete(Helios_wifi_read_mutex);
+        Helios_wifi_read_mutex = 0;
+    }
+       
+       for (int i = 0; i < 4; i++) {
+               if (wifi->data_ind[i] != 0)
+       {
+                       Helios_MsgQ_Delete(wifi->data_ind[i]);
+                       wifi->data_ind[i] = 0;
+               }
+       }
+
+    if (wifi_threadid != 0)
+    {
+        Helios_Thread_Delete(wifi_threadid);
+        wifi_threadid = 0;
+    }
+
+    if (wifi_Sema != 0)
+    {
+        Helios_Semaphore_Release(wifi_Sema);
+        Helios_Semaphore_Delete(wifi_Sema);
+        wifi_Sema = 0;
+    }
+
+    free(wifi);
+    wifi_flag = -1;
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qpy_wifistop_obj, 0, 1, wifi_stop);
+
+#if MICROPY_QPY_MODULE_WIFI
+int Helios_wifi_rb_init(Helios_wifi_ring_buf_t *rb)
+{
+    if (NULL == rb)
+    {
+        QPY_WIFI_LOG("wifi: ring buffer NULL \n");
+        return -1;
+    }
+
+    rb->rpos = 0;
+    rb->wpos = 0;
+    return 0;
+}
+
+int Helios_wifi_rb_free_space(Helios_wifi_ring_buf_t *rb)
+{
+    int cur_data_len = 0;
+
+    cur_data_len = (rb->wpos + rb->capacity + 1 - rb->rpos) % (rb->capacity + 1);
+
+    return (rb->capacity - cur_data_len);
+}
+
+int Helios_wifi_rb_data_space(Helios_wifi_ring_buf_t *rb)
+{
+    int cur_data_len = 0;
+
+    cur_data_len = (rb->wpos + rb->capacity + 1 - rb->rpos) % (rb->capacity + 1);
+
+    return cur_data_len;
+}
+
+int Helios_wifi_rb_write(Helios_wifi_ring_buf_t *rb, unsigned char *data, int len)
+{
+    int j = 0;
+    int cur_free_len = 0, write_len = 0;
+
+
+    if (NULL == rb || NULL == data || 0 == len)
+    {
+        return -1;
+    }
+       Helios_Mutex_Lock(Helios_wifi_read_mutex, HELIOS_WAIT_FOREVER);
+
+    cur_free_len = Helios_wifi_rb_free_space(rb);
+    if (0 == cur_free_len || cur_free_len < len )
+    {
+       if (Helios_wifi_read_mutex != 0)
+       {
+               Helios_Mutex_Unlock(Helios_wifi_read_mutex);
+       }
+        return 0;
+    }
+       write_len = len;
+    for (; j < write_len; j++)
+    {
+        rb->data[rb->wpos] = data[j];
+        rb->wpos = (rb->wpos + 1) % (rb->capacity + 1);
+    }
+
+       if (Helios_wifi_read_mutex != 0)
+       {
+               Helios_Mutex_Unlock(Helios_wifi_read_mutex);
+       }
+
+    return write_len;
+}
+
+int Helios_wifi_rb_read(Helios_wifi_ring_buf_t *rb, unsigned char *data, int len)
+{
+    int i = 0;
+    int cur_data_len = 0, read_len = 0;
+
+    if (NULL == rb || NULL == data || 0 == len)
+    {
+        return -1;
+    }
+
+       Helios_Mutex_Lock(Helios_wifi_read_mutex, HELIOS_WAIT_FOREVER);
+
+    cur_data_len = Helios_wifi_rb_data_space(rb);
+    if (0 == cur_data_len)
+    {
+       if (Helios_wifi_read_mutex != 0)
+       {
+               Helios_Mutex_Unlock(Helios_wifi_read_mutex);
+       }
+        return 0;
+    }
+    if (cur_data_len < len)
+    {
+        read_len = cur_data_len;
+    }
+    else
+    {
+        read_len = len;
+    }
+
+    for (i = 0; i < read_len; i++)
+    {
+        data[i] = rb->data[rb->rpos];
+        //mp_printf(&mp_plat_print, "%c", data[i]);
+        rb->rpos = (rb->rpos + 1) % (rb->capacity + 1);
+    }
+
+       if (Helios_wifi_read_mutex != 0)
+    {
+       Helios_Mutex_Unlock(Helios_wifi_read_mutex);
+    }
+
+    return read_len;
+}
+#endif
+
+STATIC const mp_rom_map_elem_t mp_module_wifi_globals_table[] = {
+    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_wifi) },
+    { MP_ROM_QSTR(MP_QSTR_setwifi), MP_ROM_PTR(&qpy_setwifi_obj) },
+    { MP_ROM_QSTR(MP_QSTR_send_atcmd), MP_ROM_PTR(&qpy_sendatcmd_obj) },
+    { MP_ROM_QSTR(MP_QSTR_setCallback), MP_ROM_PTR(&qpy_register_usr_callback_obj) },
+    { MP_ROM_QSTR(MP_QSTR_setwififlag), MP_ROM_PTR(&qpy_setwififlag_obj) },
+    { MP_ROM_QSTR(MP_QSTR_wifistop), MP_ROM_PTR(&qpy_wifistop_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(mp_module_wifi_globals, mp_module_wifi_globals_table);
+
+const mp_obj_module_t mp_module_wifi = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&mp_module_wifi_globals,
+};
+#endif
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modwifi.h b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/modwifi.h
new file mode 100644 (file)
index 0000000..190e7de
--- /dev/null
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if MICROPY_QPY_MODULE_WIFI
+
+#include "helios_os.h"
+#include "helios_uart.h"
+#include "helios_gpio.h"
+#include "helios_pin.h"
+#include "helios_debug.h"
+#include "callbackdeal.h"
+#include "helios_ringbuf.h"
+
+typedef struct _wifi_obj_t {
+    //mp_obj_base_t base;
+    unsigned int uart_num;
+    Helios_UARTConfig config;
+    Helios_Mutex_t mutex;
+    char recvdata[2048];
+    unsigned int recvlen;
+       Helios_MsgQ_t data_ind[4];
+} wifi_obj_t;
+
+int _wifi_send_atcmd(char * atcmd, int size);
+int wifi_ipd_data(char *readbuffer, int readsize);
+
+#define MICROPY_QPY_MODULE_WIFI_RINGBUFF 1
+
+#if MICROPY_QPY_MODULE_WIFI_RINGBUFF
+typedef struct Helios_wifi_ring_buf_struct
+{
+    int capacity;
+    int rpos;
+    int wpos;
+    int peer_closed;
+    Helios_Sem_t wcond;
+    Helios_Sem_t rcond;
+    unsigned char data[0];
+} Helios_wifi_ring_buf_t;
+
+int Helios_wifi_rb_init(Helios_wifi_ring_buf_t *rb);
+int Helios_wifi_rb_read(Helios_wifi_ring_buf_t *rb, unsigned char *data, int len);
+int Helios_wifi_rb_write(Helios_wifi_ring_buf_t *rb, unsigned char *data, int len);
+int Helios_wifi_rb_data_space(Helios_wifi_ring_buf_t *rb);
+int Helios_wifi_rb_free_space(Helios_wifi_ring_buf_t *rb);
+#endif
+
+#endif
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/nfc_sl6320.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/nfc_sl6320.c
new file mode 100644 (file)
index 0000000..3c7d4a0
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**************************************************************************
+ @file modSL6320.c
+ @brief        camera module interface package.
+
+ DESCRIPTION
+ This module provide the camera playback interface of micropython.
+
+ INITIALIZATION AND SEQUENCING REQUIREMENTS
+
+
+ ===========================================================================
+ Copyright (c) 2018 Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ Quectel Wireless Solution Proprietary and Confidential.
+ ===========================================================================
+
+                                               EDIT HISTORY FOR FILE
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+WHEN           WHO                     WHAT,WHERE,WHY
+----------  ---------   ---------------------------------------------------
+4/12/2021  felixe.ye   Create.
+**************************************************************************/
+
+//////////////////////////////////////////////////////////////////////////////
+// Includes
+//////////////////////////////////////////////////////////////////////////////
+#include <stdio.h>
+#include "runtime.h"
+#include <stdlib.h>
+#include <math.h>
+#include "mphalport.h"
+#include "compile.h"
+#include "repl.h"
+#include "mperrno.h"
+#include "binary.h"
+#include <string.h>
+
+#if MICROPY_QPY_NFC_SL6320
+
+#include "helios_gpio.h"
+#include "helios_iic.h"
+#include "helios_pin.h"
+#include "helios_nfc_sl6320.h"
+
+
+#include "callbackdeal.h"
+
+#include "helios_debug.h"
+#define SL6320_LOG(msg, ...)      custom_log("SL6320", msg, ##__VA_ARGS__)
+
+
+
+typedef struct _SL6320_obj_t
+{
+    mp_obj_base_t base;
+       NFC_SL6320_S sl6320_info;
+       c_callback_t cb;
+} SL6320_obj_t;
+
+
+#define sl6320_check_para(Conditions, raise)                                             \
+               do{                                                                                                                                             \
+                       if (Conditions) {          \
+                               if (raise) {                                                                                                            \
+                                       mp_raise_ValueError(MP_ERROR_TEXT("Parameter error, please check the parameter"));      \
+                               } else {                                                                                                                        \
+                                       return MP_OBJ_NEW_SMALL_INT(-1);   \
+                               }                                                                                                                                       \
+                       }                                                                                                                                               \
+               } while (0)
+
+
+
+
+STATIC mp_obj_t SL6320_make_new(const mp_obj_type_t *type,
+                               size_t n_args,
+                               size_t n_kw,
+                               const mp_obj_t *all_args)
+{
+    enum{
+        ARG_mode,
+               ARG_en_gpio,
+               ARG_io_en_gpio,
+               ARG_dwl_gpio,
+               ARG_irq_gpio,
+               ARG_polling_cb,
+               ARG_upgrade,
+               ARG_interface,
+               ARG_i2c_port,
+               ARG_i2c_mode,
+               ARG_i2c_group,
+               ARG_spi_port,
+               ARG_spi_mode,
+               ARG_spi_clk,
+               ARG_spi_group,
+    };
+
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_mode, MP_ARG_INT, {.u_int = NFC_MODE_LISTEN}},
+        { MP_QSTR_en_gpio, MP_ARG_INT, {.u_int = HELIOS_GPIO41}},
+        { MP_QSTR_io_en_gpio, MP_ARG_INT, {.u_int = HELIOS_GPIO17}},
+        { MP_QSTR_dwl_gpio, MP_ARG_INT, {.u_int = HELIOS_GPIO40}},  
+        { MP_QSTR_irq_gpio, MP_ARG_INT, {.u_int = HELIOS_GPIO11}},
+        
+        { MP_QSTR_polling_cb, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+               { MP_QSTR_upgrade, MP_ARG_INT, {.u_int = 0}},
+        
+        { MP_QSTR_interface, MP_ARG_INT, {.u_int = NFC_INTERFACE_I2C}},
+        { MP_QSTR_i2c_port, MP_ARG_INT, {.u_int = HELIOS_I2C2}},
+        { MP_QSTR_i2c_mode, MP_ARG_INT, {.u_int = HELIOS_STANDARD_MODE}},
+        { MP_QSTR_i2c_group, MP_ARG_INT, {.u_int = 0}},
+        { MP_QSTR_spi_port, MP_ARG_INT, {.u_int = HELIOS_SPI0}},
+        { MP_QSTR_spi_mode, MP_ARG_INT, {.u_int = HELIOS_SPIMODE0}},
+        { MP_QSTR_spi_clk, MP_ARG_INT, {.u_int = 13000}},
+        { MP_QSTR_spi_group, MP_ARG_INT, {.u_int = 0}},
+    };
+
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+    SL6320_obj_t *self = m_new_obj(SL6320_obj_t);
+    self->base.type = type;
+
+       NFC_SL6320_S para = {0};
+       para.mode = args[ARG_mode].u_int;
+       para.interface = args[ARG_interface].u_int;
+       if(args[ARG_interface].u_int == NFC_INTERFACE_I2C) {
+               para.interface_info.i2c_st.port = args[ARG_i2c_port].u_int;
+               para.interface_info.i2c_st.mode = args[ARG_i2c_mode].u_int;
+               para.interface_info.i2c_st.group = args[ARG_i2c_group].u_int;
+       }
+       para.en_gpio = args[ARG_en_gpio].u_int;
+       para.io_en_gpio = args[ARG_io_en_gpio].u_int;
+       para.dwl_gpio = args[ARG_dwl_gpio].u_int;
+       para.dat_irq_gpio = args[ARG_irq_gpio].u_int;
+       para.cb = NULL;
+       para.firmware_upgrade = args[ARG_upgrade].u_int;
+
+       sl6320_check_para(para.mode >= NFC_MODE_MAX, true);
+       sl6320_check_para(para.interface >= NFC_INTERFACE_MAX, true);
+       
+
+       SL6320_LOG("sl6320 para: mode[%d], interface[%d],i2c_port[%d],i2c_mode[%d],i2c_group[%d],en_gpio[%d],io_gpio[%d],       \
+               dwl_gpio:[%d],irq_gpio[%d],cb[%x],upgrade[%d]\n", para.mode, para.interface, para.interface_info.i2c_st.port,   \
+               para.interface_info.i2c_st.mode, para.interface_info.i2c_st.group, para.en_gpio, para.io_en_gpio, para.dwl_gpio, \
+               para.dat_irq_gpio, para.cb, para.firmware_upgrade);
+
+       if(Helios_NFC_SL6320_init(&para) != 0) {
+               mp_raise_ValueError(MP_ERROR_TEXT("nfc sl6320 init failed"));
+       }
+
+       memcpy(&self->sl6320_info, &para, sizeof(NFC_SL6320_S));
+
+    return MP_OBJ_FROM_PTR(self);
+}
+
+
+
+STATIC mp_obj_t mp_SL6320_deinit(mp_obj_t self_in)
+{
+       SL6320_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       Helios_NFC_SL6320_deinit();
+       self->sl6320_info.mode = NFC_MODE_MAX;
+       return mp_const_none;
+       
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_deinit_SL6320_obj, mp_SL6320_deinit);
+
+
+STATIC mp_obj_t mp_SL6320_mode(size_t n_args, const mp_obj_t* args) {
+    SL6320_obj_t* self = MP_OBJ_TO_PTR(args[0]);
+    if (n_args > 1) {
+        NFC_SL6320_MODE new_mode = mp_obj_get_int(args[1]);
+       
+               sl6320_check_para(new_mode >= NFC_MODE_MAX, true);
+
+               if(new_mode == self->sl6320_info.mode) {
+                       mp_raise_ValueError(MP_ERROR_TEXT("ERR_ALREADY_IN_THIS_MODE"));
+               }
+
+               Helios_NFC_SL6320_deinit();
+               self->sl6320_info.mode = new_mode;
+               
+               if(Helios_NFC_SL6320_init(&self->sl6320_info) != 0) {
+                       mp_raise_ValueError(MP_ERROR_TEXT("nfc mode switching failed"));
+               }
+               
+        return mp_const_none;
+    } else {
+        return MP_OBJ_NEW_SMALL_INT(self->sl6320_info.mode);
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_mode_SL6320_obj, 1, 2, mp_SL6320_mode);
+
+STATIC mp_obj_t mp_SL6320_polling_cb(mp_obj_t self_in, mp_obj_t cb)
+{
+       SL6320_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       if(self->sl6320_info.mode != NFC_MODE_POLLING)
+       {
+               mp_raise_ValueError(MP_ERROR_TEXT("Nfc is not in polling mode and cannot be set"));
+       }
+       //TODO
+       
+       return mp_const_none;
+       
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_SL6320_register_polling_cb_obj, mp_SL6320_polling_cb);
+
+
+
+STATIC const mp_rom_map_elem_t SL6320_locals_dict_table[] = {
+       { MP_ROM_QSTR(MP_QSTR___del__),         MP_ROM_PTR(&mp_deinit_SL6320_obj) },
+    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mp_deinit_SL6320_obj) },
+    { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&mp_mode_SL6320_obj) },
+       { MP_ROM_QSTR(MP_QSTR_polling_cb), MP_ROM_PTR(&mp_SL6320_register_polling_cb_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(SL6320_locals_dict, SL6320_locals_dict_table);
+
+const mp_obj_type_t NFC_SL6320_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_SL6320,
+    .make_new = SL6320_make_new,
+    .locals_dict = (mp_obj_dict_t*)&SL6320_locals_dict,
+};
+
+
+
+#endif
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/sensor_VC9202.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/sensor_VC9202.c
new file mode 100644 (file)
index 0000000..1db6534
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "mpconfig.h"
+#include "smallint.h"
+#include "runtime.h"
+#include "gc.h"
+#include "mphal.h"
+
+#if MICROPY_QPY_SENSOR_VC9202
+#include "helios_os.h"
+#include "helios_extint.h"
+#include "helios_debug.h"
+#include "callbackdeal.h"
+#include "helios_iic.h"
+#include "vc9202_user.h"
+#define SENSOR_VC9202_LOG(msg, ...)      custom_log("VC9202", msg, ##__VA_ARGS__)
+
+typedef struct {
+    mp_obj_base_t base;
+    mp_int_t i2c_num;
+       mp_int_t int_gpio;
+       mp_int_t samp_time;     //unit ms,suggested value 400
+       mp_int_t work_mode; //see enum WorkModeTypeDef define
+       mp_int_t sport_mode; //see enum AlgoSportMode define
+       mp_int_t spo2_alg_mode; //
+       c_callback_t callback;
+} vc9202_obj_t;
+
+static vc9202_obj_t *vc9202_obj = NULL;
+
+
+static Helios_Thread_t thread_vc9202 = 0;
+static Helios_Sem_t vc9202_Sema = 0;
+
+
+static void vc9202_int_handler(void)                                                               
+{      
+    if(vc9202_Sema)
+    {
+               Helios_Semaphore_Release(vc9202_Sema);
+       }
+       Helios_ExtInt_Enable(vc9202_obj->int_gpio);                                                                                                                                                                                                 
+}              
+
+static void entry_vc9202(void * argv)
+{
+       int status = 0;
+       WorkModeTypeDef work_mode;//vc9202 work mode 
+       AlgoSportMode sport_mode;
+       unsigned char spo2_alg_mode;//spo2 measure mode 1:normal 2:passive mode
+       AlgoCalcResultsTypeDef vc9202_result_data;
+       while(1)
+       {
+               status = Helios_Semaphore_Acquire(vc9202_Sema, HELIOS_WAIT_FOREVER);
+               if(status == -1)
+               {
+                       SENSOR_VC9202_LOG("vc9202 wait semaphore err");
+                       break;
+               }
+               work_mode = vc9202_get_current_work_mode();
+               
+               sport_mode = vc9202_get_AlgoSpotMode();
+               spo2_alg_mode = get_spo2_alg_mode();
+               
+               vc9202_usr_interrupt_handler(sport_mode, spo2_alg_mode);//get vc9202 data       
+
+               if(get_data_flag())//occur FIFO event or PS event
+               {
+                       reset_data_flag();
+                       if(work_mode != 6)
+                       {
+                           vc9202_result_data = get_calc_results_vc9202();
+                           
+                           st_CallBack_Sensor_VC9202 *cb_data = malloc(sizeof(st_CallBack_Sensor_VC9202));  
+                           if(NULL != cb_data)
+                           {                                                                
+                                   cb_data->work_mode = work_mode;
+                                   if(work_mode ==WORK_MODE_HR)
+                                   {
+                                       cb_data->value = vc9202_result_data.hr_rate; 
+                                       cb_data->measure_mode = sport_mode;
+                                   }
+                                   else if(work_mode == WORK_MODE_SPO2)
+                                   {
+                                               cb_data->value = vc9202_result_data.spo2_val; 
+                                               cb_data->measure_mode = spo2_alg_mode;
+                                   }
+                                   cb_data->callback = vc9202_obj->callback;
+                                   if(qpy_send_msg_to_callback_deal_thread(CALLBACK_TYPE_ID_VC9202, cb_data))          
+                                   {                                                                                                                                                           
+                                               free(cb_data);                                                                                                                          
+                                   }                                                                                                                                                           
+                               } 
+                       }
+               }
+
+
+
+       }
+}
+
+enum { ARG_i2c_num, ARG_int_gpio,  ARG_callback,ARG_samp_time , ARG_work_mode, ARG_sport_mode,ARG_spo2_alg_mode};
+STATIC const mp_arg_t vc9202_allowed_args[] = 
+{
+    { MP_QSTR_i2c_num,       MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+    { MP_QSTR_int_gpio,      MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0xff} },
+    { MP_QSTR_callback,         MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+    { MP_QSTR_samp_time,     MP_ARG_INT, {.u_int = 400} },
+    { MP_QSTR_work_mode,     MP_ARG_INT, {.u_int = 1} },
+       { MP_QSTR_sport_mode,    MP_ARG_INT, {.u_int = 0} },
+       { MP_QSTR_spo2_alg_mode,    MP_ARG_INT, {.u_int = 1} },//1:normal 2:passive mode
+};
+#define VC9202_ARGS_TAB_SIZE MP_ARRAY_SIZE(vc9202_allowed_args)
+
+const mp_obj_type_t sensor_vc9202_type;
+
+STATIC mp_obj_t VC9202_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) 
+{
+    // type_in == extint_obj_type
+
+    // parse args
+    mp_arg_val_t vals[VC9202_ARGS_TAB_SIZE];
+    mp_arg_parse_all_kw_array(n_args, n_kw, args, VC9202_ARGS_TAB_SIZE, vc9202_allowed_args, vals);
+
+
+       //SENSOR_VC9202_LOG("vc9202 i2c_num:%d,int_gpio:%d,samp_time:%d,wor_mode:%d,sport_mode:%d,spo2_alg_mode:%d",
+       //vals[ARG_i2c_num].u_int,vals[ARG_int_gpio].u_int,vals[ARG_samp_time].u_int,
+       //vals[ARG_work_mode].u_int,vals[ARG_sport_mode].u_int,vals[ARG_spo2_alg_mode].u_int);
+       
+       if (vals[ARG_int_gpio].u_int < HELIOS_GPIO0 || vals[ARG_int_gpio].u_int > HELIOS_GPIOMAX) 
+       {
+               mp_raise_ValueError("invalid int_gpio value");
+       }
+/*
+       if (vals[ARG_rst_gpio].u_int < HELIOS_GPIO0 || vals[ARG_rst_gpio].u_int > HELIOS_GPIOMAX) 
+       {
+               mp_raise_ValueError("invalid rst_gpio value");
+       }
+*/     
+       if (vc9202_obj == NULL)
+       {
+               vc9202_obj = m_new_obj_with_finaliser(vc9202_obj_t);
+       }
+       vc9202_obj_t *self = vc9202_obj;
+       self->base.type = &sensor_vc9202_type;
+       self->i2c_num = vals[ARG_i2c_num].u_int;        
+       self->int_gpio = vals[ARG_int_gpio].u_int;
+       self->samp_time = vals[ARG_samp_time].u_int;
+       self->work_mode = vals[ARG_work_mode].u_int;
+       self->sport_mode = vals[ARG_sport_mode].u_int;
+       self->spo2_alg_mode = vals[ARG_spo2_alg_mode].u_int;
+       
+       mp_sched_schedule_callback_register(&self->callback, vals[ARG_callback].u_obj);
+
+#if 1
+       //init iic
+       Helios_I2C_Deinit((Helios_I2CEnum) self->i2c_num);
+    if(Helios_I2C_Init((Helios_I2CEnum) self->i2c_num, (Helios_I2CMode) 0))
+    {
+               mp_raise_ValueError(MP_ERROR_TEXT("vc9202 i2c initialization failed"));
+    }
+#endif
+
+       //init int gpio
+       Helios_ExtIntStruct extint_struct = {0};
+       extint_struct.gpio_trigger = HELIOS_EDGE_TRIGGER;
+       extint_struct.gpio_edge = HELIOS_EDGE_FALLING;
+       extint_struct.gpio_debounce = HELIOS_DEBOUNCE_EN;
+       extint_struct.gpio_pull = HELIOS_PULL_NONE;
+       extint_struct.eint_cb = NULL;
+       extint_struct.wakeup_eint_cb = vc9202_int_handler;
+
+       Helios_ExtInt_Deinit((Helios_GPIONum) self->int_gpio);
+
+       if(0 != Helios_ExtInt_Init((Helios_GPIONum) self->int_gpio,  &extint_struct)) 
+       {
+               mp_raise_ValueError(MP_ERROR_TEXT("vc9202 Interrupt initialization failed"));
+       }
+
+       if(Helios_ExtInt_Enable((Helios_GPIONum) self->int_gpio))
+       {
+               mp_raise_ValueError(MP_ERROR_TEXT("vc9202 Interrupt enable failed"));
+       }
+
+       if(vc9202_Sema == 0)
+       {
+               vc9202_Sema = Helios_Semaphore_Create(5, 0);
+               if(vc9202_Sema == 0)
+               {
+                       mp_raise_ValueError(MP_ERROR_TEXT("vc9202 creat semaphore failed"));
+               }
+       }
+
+       vc9202_mutex_creat();
+       
+       if(thread_vc9202 == 0)
+       {
+               Helios_ThreadAttr ThreadAttr = 
+               {
+               .name = "vc9202_thread",
+               .stack_size = 2048*2,
+#if defined(PLAT_Unisoc) || defined(PLAT_EIGEN)
+               .priority = 92,
+#else
+                       .priority = 90,
+#endif
+               .entry = entry_vc9202,
+               .argv = NULL
+           };
+               thread_vc9202 = Helios_Thread_Create(&ThreadAttr);
+               if(thread_vc9202 == 0)
+               {
+                       mp_raise_ValueError(MP_ERROR_TEXT("vc9202 creat thread failed"));
+               }
+       }
+       //Helios_log_mask_set(32, 1);
+       set_vc9202_i2c_num((Helios_I2CEnum) self->i2c_num);
+       vc9202_set_AlgoSpotMode(self->sport_mode);
+       read_wear_param_bioin();
+       if(self->work_mode != WORK_MODE_FACTORY)
+       {
+               reset_bio();
+       }
+    return MP_OBJ_FROM_PTR(self);
+}
+
+
+STATIC void vc9202_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) 
+{
+    vc9202_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_printf(print, "<i2c_num=%u,int gpio=%u>", self->i2c_num,self->int_gpio);
+}
+
+
+STATIC mp_obj_t vc9202_Deinit(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       int ret = -1;
+
+       Helios_Thread_Delete(thread_vc9202);
+       thread_vc9202 = 0;
+       Helios_Semaphore_Delete(vc9202_Sema);
+       vc9202_Sema = 0;
+
+       vc9202_mutex_delete();
+       vc9202_obj = NULL;
+       if((0 == Helios_ExtInt_Disable((Helios_GPIONum) self->int_gpio)) && (0 == Helios_ExtInt_Deinit((Helios_GPIONum) self->int_gpio))) 
+       {
+               ret = 0;
+       }
+       return mp_obj_new_int(ret);     
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_Deinit_obj, vc9202_Deinit);
+
+
+STATIC mp_obj_t vc9202_set_workmode(mp_obj_t self_in, mp_obj_t workmode) 
+{
+    vc9202_obj_t *self = self_in;
+       InitParamTypeDef pInitParam = {0};
+    int mode = mp_obj_get_int(workmode);
+    
+       if((mode != WORK_MODE_HR) && (mode != WORK_MODE_SPO2) && (mode != WORK_MODE_FACTORY))
+       {
+               mp_raise_ValueError(MP_ERROR_TEXT("Invalid vc9202 work mode"));
+       }
+       vc9202_set_work_mode((WorkModeTypeDef)mode);
+       self->work_mode = mode;
+       pInitParam.sampling_gap_time = self->samp_time;
+       pInitParam.work_mode = self->work_mode;
+       if(self->work_mode != WORK_MODE_FACTORY)
+       {
+               reset_bio();
+       }
+    vc9202_usr_init(&pInitParam);
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vc9202_set_work_mode_obj, vc9202_set_workmode);
+
+STATIC mp_obj_t vc9202_get_work_mode(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = self_in;
+    int mode;
+    
+       mode = self->work_mode;
+    return mp_obj_new_int(mode);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_get_work_mode_obj, vc9202_get_work_mode);
+
+//sportmode only for HR 
+STATIC mp_obj_t vc9202_set_sport_mode(mp_obj_t self_in, mp_obj_t sport_mode) 
+{
+    vc9202_obj_t *self = self_in;
+    int mode = mp_obj_get_int(sport_mode);
+    
+       if((mode > SPORT_TYPE_PERIODIC_MONITORING) || (mode < SPORT_TYPE_NORMAL))
+       {
+               mp_raise_ValueError(MP_ERROR_TEXT("Invalid vc9202 sport mode"));
+       }
+
+       vc9202_set_AlgoSpotMode(mode);
+       self->sport_mode = mode;
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vc9202_set_sport_mode_obj, vc9202_set_sport_mode);
+
+STATIC mp_obj_t vc9202_get_sport_mode(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = self_in;
+    return mp_obj_new_int(self->sport_mode);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_get_sport_mode_obj, vc9202_get_sport_mode);
+
+//only for spo2 work mode 
+STATIC mp_obj_t vc9202_set_spo2_alg_mode(mp_obj_t self_in, mp_obj_t spo2_alg_mode) 
+{
+    vc9202_obj_t *self = self_in;
+    int mode = mp_obj_get_int(spo2_alg_mode);
+    
+       if((mode != 2) && (mode != 1))
+       {
+               mp_raise_ValueError(MP_ERROR_TEXT("Invalid vc9202 spo2_alg_mode"));
+       }
+       
+       set_spo2_alg_mode(mode);
+       self->spo2_alg_mode = mode;
+       
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vc9202_set_spo2_alg_mode_obj, vc9202_set_spo2_alg_mode);
+
+STATIC mp_obj_t vc9202_get_spo2_alg_mode(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = self_in;
+    return mp_obj_new_int(self->spo2_alg_mode);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_get_spo2_alg_mode_obj, vc9202_get_spo2_alg_mode);
+
+STATIC mp_obj_t vc9202_start_samp(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = self_in;
+    //vc9202_usr_start_sampling();
+    //call init is better. suggested by supplier
+    InitParamTypeDef pInitParam = {0};
+    pInitParam.sampling_gap_time = self->samp_time;
+       pInitParam.work_mode = self->work_mode;
+    vc9202_usr_init(&pInitParam);
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_start_samp_obj, vc9202_start_samp);
+
+STATIC mp_obj_t vc9202_stop_samp(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = self_in;
+    
+    vc9202_usr_stop_sampling();
+    
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_stop_samp_obj, vc9202_stop_samp);
+
+//return 1: wear 0:not wear
+STATIC mp_obj_t vc9202_get_wear_status(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = self_in;
+    int ret = 0;
+    if(get_vc9202_open_flag() == 0)
+    {
+               ret = -1;
+    }
+    else
+    {
+           ret = get_wear_status_for_user();
+           //SENSOR_VC9202_LOG("JIMMY 2 WEAR=%d",ret);
+       }
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_get_wear_status_obj, vc9202_get_wear_status);
+
+//py need call this api at least 10 times wtihin 400ms,for vc9202 need 10 gpoup g_sensor data every 400ms calculate HR 
+STATIC mp_obj_t vc9202_update_single_gsensor_raw_data(mp_uint_t n_args, const mp_obj_t *args) 
+{
+    vc9202_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+       int16_t data_x[1];
+       int16_t data_y[1];
+       int16_t data_z[1];
+    data_x[0] = mp_obj_get_int(args[1]);//this data is raw data read from g_sensor reg,see gsensor datasheet
+    data_y[0] = mp_obj_get_int(args[2]);
+    data_z[0] = mp_obj_get_int(args[3]);
+    //SENSOR_VC9202_LOG("VC9202 update data 1 x:0x%x,y:0x%x,z0x%x",data_x,data_y,data_z);
+       update_gsensor_raw_data(1,data_x,data_y,data_z);
+    
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vc9202_update_single_gsensor_raw_data_obj, 4, 4, vc9202_update_single_gsensor_raw_data);
+
+//this api allow user input multi data 
+STATIC mp_obj_t vc9202_update_gsensor_raw_data(mp_uint_t n_args, const mp_obj_t *args) 
+{
+    uint8_t i;
+       size_t len_x,len_y,len_z;
+       mp_obj_t *items_x;
+       mp_obj_t *items_y;
+       mp_obj_t *items_z;
+       int16_t data_x[40]={0};
+       int16_t data_y[40]={0};
+       int16_t data_z[40]={0};
+    vc9202_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    int8_t data_len = mp_obj_get_int(args[1]);//
+
+    mp_obj_get_array(args[2], &len_x, &items_x);
+    mp_obj_get_array(args[3], &len_y, &items_y);
+    mp_obj_get_array(args[4], &len_z, &items_z);
+
+       if((len_x != data_len) || (len_y != data_len) || (len_z != data_len))
+       {
+               mp_raise_ValueError(MP_ERROR_TEXT("datalen conflicting"));
+       }
+    for(i=0;i<data_len;i++)
+       {
+           data_x[i] = mp_obj_get_int(items_x[i]);
+           data_y[i] = mp_obj_get_int(items_y[i]);
+           data_z[i] = mp_obj_get_int(items_z[i]);
+    }
+    
+    //SENSOR_VC9202_LOG("VC9202 update data 1 x:0x%x,y:0x%x,z0x%x",data_x,data_y,data_z);
+       update_gsensor_raw_data(data_len,data_x,data_y,data_z);
+    
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vc9202_update_gsensor_raw_data_obj, 5, 5, vc9202_update_gsensor_raw_data);
+
+//accord to the actual config para of g_sensor   VC9202 require:sampling_rate >= 25Hz ;sensing_range >=±4G; effective_bit:8bits indicates ±1G
+STATIC mp_obj_t vc9202_set_gsensor_type(mp_uint_t n_args, const mp_obj_t *args) 
+{
+    vc9202_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+    int16_t _sampling_rate = mp_obj_get_int(args[1]);//eg. 25 means gsensor generate 25 group xyz datas per sencond
+    int16_t _sensing_range = mp_obj_get_int(args[2]);//eg. 4G means gsensor measuring range
+    int16_t _effective_bits = mp_obj_get_int(args[3]);// no need care ,algo not use
+    //SENSOR_VC9202_LOG("VC9202 set gsensor_type 1 %d,%d,%d",_sampling_rate,_sensing_range,_effective_bits);
+       set_g_sensor_type(_sampling_rate,_sensing_range,_effective_bits); 
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vc9202_set_gsensor_type_obj, 4, 4, vc9202_set_gsensor_type);
+
+//return bio value(only in work mode FACTORT_MODE) ,wear_param_bioin = (bio(not wear)-bio(wear))/2
+STATIC mp_obj_t vc9202_get_bio(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = self_in;
+    int ret = 0;
+    ret = get_bio();
+    
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_get_bio_obj, vc9202_get_bio);
+
+//Set wear_param_bioin ,will write to NV filesystem,and will read form NV next time 9202 init
+STATIC mp_obj_t vc9202_set_wear_param_bioin(mp_obj_t self_in, mp_obj_t bioin)
+{
+    vc9202_obj_t *self = self_in;
+    int value = mp_obj_get_int(bioin);
+    
+       if((value<=0)||(value >1000))
+       {
+               mp_raise_ValueError(MP_ERROR_TEXT("value error"));
+       }
+       
+       set_wear_param_bioin(value);
+       
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vc9202_set_wear_param_bioin_obj, vc9202_set_wear_param_bioin);
+
+//return wear_param_bioin
+STATIC mp_obj_t vc9202_get_wear_param_bioin(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = self_in;
+    int ret = 0;
+    ret = get_wear_param_bioin();
+    
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_get_wear_param_bioin_obj, vc9202_get_wear_param_bioin);
+
+//return 0:not calibrated 1:calibrated
+STATIC mp_obj_t vc9202_is_wear_param_bioin_calibrated(mp_obj_t self_in) 
+{
+    vc9202_obj_t *self = self_in;
+    int ret = 0;
+    
+    if(is_wear_param_calibrated() == 0)//not calibrated
+    {
+               ret = 0;
+    }
+    else
+    {
+               ret = 1;
+    }
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_is_wear_param_bioin_calibrated_obj, vc9202_is_wear_param_bioin_calibrated);
+
+//Set wear_param_bioin ,will write to NV filesystem,and will read form NV next time 9202 init
+STATIC mp_obj_t vc9202_set_default_wear_param_bioin(mp_obj_t self_in, mp_obj_t bioin)
+{
+    vc9202_obj_t *self = self_in;
+    int ret = 0;
+    int value = mp_obj_get_int(bioin);
+    
+       if((value<=0)||(value >1000))
+       {
+               mp_raise_ValueError(MP_ERROR_TEXT("value error"));
+       }
+       
+       if(is_wear_param_calibrated() == 0)//not calibrated
+       {
+               set_default_wear_param_bioin(value);
+       }
+       else//already calibrated
+       {
+               ret = -1;
+       }
+       
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vc9202_set_default_wear_param_bioin_obj, vc9202_set_default_wear_param_bioin);
+#if 0
+STATIC mp_obj_t vc9202_delete_nv(mp_obj_t self_in)
+{
+    vc9202_obj_t *self = self_in;
+    delete_nv();
+       
+    return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vc9202_delete_nv_obj, vc9202_delete_nv);
+#endif
+
+STATIC const mp_rom_map_elem_t sensor_vc9202_locals_dict_table[] = {
+       { MP_ROM_QSTR(MP_QSTR___del__),         MP_ROM_PTR(&vc9202_Deinit_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_work_mode),   MP_ROM_PTR(&vc9202_set_work_mode_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_work_mode),   MP_ROM_PTR(&vc9202_get_work_mode_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_sport_mode),  MP_ROM_PTR(&vc9202_set_sport_mode_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_sport_mode),  MP_ROM_PTR(&vc9202_get_sport_mode_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_spo2_mode),   MP_ROM_PTR(&vc9202_set_spo2_alg_mode_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_spo2_mode),   MP_ROM_PTR(&vc9202_get_spo2_alg_mode_obj) },
+       { MP_ROM_QSTR(MP_QSTR_start_samp),      MP_ROM_PTR(&vc9202_start_samp_obj) },
+       { MP_ROM_QSTR(MP_QSTR_stop_samp),       MP_ROM_PTR(&vc9202_stop_samp_obj) },
+       { MP_ROM_QSTR(MP_QSTR_wear_status),     MP_ROM_PTR(&vc9202_get_wear_status_obj) },
+       { MP_ROM_QSTR(MP_QSTR_update_single_gsensor_data),      MP_ROM_PTR(&vc9202_update_single_gsensor_raw_data_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_gsensor_type),        MP_ROM_PTR(&vc9202_set_gsensor_type_obj) },
+       { MP_ROM_QSTR(MP_QSTR_update_gsensor_data),     MP_ROM_PTR(&vc9202_update_gsensor_raw_data_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_bio),         MP_ROM_PTR(&vc9202_get_bio_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_wear_bioin),  MP_ROM_PTR(&vc9202_set_wear_param_bioin_obj) },
+       { MP_ROM_QSTR(MP_QSTR_get_wear_bioin),  MP_ROM_PTR(&vc9202_get_wear_param_bioin_obj) },
+       { MP_ROM_QSTR(MP_QSTR_is_wear_bioin_cali),      MP_ROM_PTR(&vc9202_is_wear_param_bioin_calibrated_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_default_wear_bioin),  MP_ROM_PTR(&vc9202_set_default_wear_param_bioin_obj) },
+       //{ MP_ROM_QSTR(MP_QSTR_vc9202_delete_nv),      MP_ROM_PTR(&vc9202_delete_nv_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(sensor_vc9202_locals_dict, sensor_vc9202_locals_dict_table);
+
+const mp_obj_type_t sensor_vc9202_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_VC9202,
+    .print = vc9202_print,
+    .make_new = VC9202_make_new,
+    .locals_dict = (mp_obj_dict_t *)&sensor_vc9202_locals_dict,
+};
+#endif //end of MICROPY_QPY_SENSOR_ICC_KEY
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/sim_esim_ipa.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/sim_esim_ipa.c
new file mode 100644 (file)
index 0000000..2dd6b59
--- /dev/null
@@ -0,0 +1,794 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "obj.h"
+#include "runtime.h"
+#include "helios_os.h"
+#include "helios_debug.h"
+#include "helios_esim.h"
+#include "mphalport.h"
+#include "string.h"
+
+#if MICROPY_QPY_MODULE_ESIM_IPA
+#define QPY_MODLPA_LOG(msg, ...)      custom_log("IPA", msg, ##__VA_ARGS__)
+#include "callbackdeal.h"
+
+typedef struct __Helios_esim_ip_event{
+    uint8_t sim_id;
+    unsigned int event_id;
+    int result;
+    void *ctx;
+}Helios_esim_event;
+
+
+#define OUT_TO_DEBUG    1
+#if     OUT_TO_DEBUG
+
+#define IPA_LOG(msg, ...)      custom_log(IPA, msg, ##__VA_ARGS__)
+
+#else
+extern void mp_hal_stdout_tx_str(const char *str);
+char ipa_sbuf[513];
+#define IPA_LOG(msg, ...) \
+{\
+    memset(ipa_sbuf,0x00,512+1); \
+    snprintf(ipa_sbuf,512,"[%s,%d]" msg "\n",__FUNCTION__,__LINE__,##__VA_ARGS__);\
+    mp_hal_stdout_tx_str(ipa_sbuf);\
+}
+
+#endif
+
+static c_callback_t *g_esim_ipa_user_callback;
+
+
+static int  qpy_esim_event_deal_profile_list(mp_obj_t data_list,Helios_Esim_Profilelistinfo_Struct *profile_list){
+ 
+    int i = 0 ;
+    mp_obj_list_append(data_list,mp_obj_new_int(profile_list->profile_num));
+    for ( i = 0 ; i <profile_list->profile_num;i++ ){
+
+        mp_obj_t data_list_buffer = mp_obj_new_list(0, NULL);
+        mp_obj_list_append(data_list_buffer,mp_obj_new_str((char *)profile_list->profile_list[i].iccid,strlen(profile_list->profile_list[i].iccid)));
+        mp_obj_list_append(data_list_buffer,mp_obj_new_int(profile_list->profile_list[i].status));
+        mp_obj_list_append(data_list_buffer,mp_obj_new_str(profile_list->profile_list[i].nickname,strlen(profile_list->profile_list[i].nickname)));
+        mp_obj_list_append(data_list_buffer,mp_obj_new_str(profile_list->profile_list[i].provider,strlen(profile_list->profile_list[i].provider)));
+        mp_obj_list_append(data_list,data_list_buffer);
+    }
+    return 0;
+}
+
+static int  qpy_esim_event_deal_notification_list(mp_obj_t data_list,Helios_Esim_LPA_Notification_list *notification_list){
+ 
+    int i = 0 ;
+    IPA_LOG("%d \n",notification_list->list_num);
+    mp_obj_list_append(data_list,mp_obj_new_int(notification_list->list_num));
+    for ( i = 0 ; i <notification_list->list_num;i++ ){
+
+        mp_obj_t data_list_buffer = mp_obj_new_list(0, NULL);
+        mp_obj_list_append(data_list_buffer,mp_obj_new_int(notification_list->notyfication_list[i].type));
+        mp_obj_list_append(data_list_buffer,mp_obj_new_int(notification_list->notyfication_list[i].seq_num));
+        mp_obj_list_append(data_list_buffer,mp_obj_new_str(notification_list->notyfication_list[i].iccid,strlen(notification_list->notyfication_list[i].iccid)));
+        mp_obj_list_append(data_list,data_list_buffer);
+    }
+    return 0;
+}
+
+static int  qpy_esim_eim_list(mp_obj_t data_list,Helios_Esim_Eim_list *esim_eim_data){
+    int i = 0 ;
+    mp_obj_list_append(data_list,mp_obj_new_int(esim_eim_data->element_num));
+    for ( i = 0 ; i <esim_eim_data->element_num;i++ ){
+        mp_obj_t data_list_buffer = mp_obj_new_list(0, NULL);
+        mp_obj_list_append(data_list_buffer,mp_obj_new_int(esim_eim_data->notyfication_list[i].status));
+        mp_obj_list_append(data_list_buffer,mp_obj_new_int(esim_eim_data->notyfication_list[i].eim_type));
+        mp_obj_list_append(data_list_buffer,mp_obj_new_str(esim_eim_data->notyfication_list[i].eim_id_info,strlen(esim_eim_data->notyfication_list[i].eim_id_info)));
+        mp_obj_list_append(data_list_buffer,mp_obj_new_str(esim_eim_data->notyfication_list[i].eim_fqdn_info,strlen(esim_eim_data->notyfication_list[i].eim_fqdn_info)));
+        mp_obj_list_append(data_list,data_list_buffer);
+    }
+    return 0;
+}
+
+static void qpy_esim_free_memory(void * ptr,unsigned int event_id){
+    if ( event_id == HELIOS_ESIM_LPA_AT_DOWN_OPT_RSP || event_id == HELIOS_ESIM_LPA_PROFILE_TRANS_RSP ){
+        Helios_Esim_uart_download_resp *data_free = (Helios_Esim_uart_download_resp *)ptr;
+        if ( data_free->playload_info != NULL ){
+            free(data_free->playload_info);
+        }
+    }
+    if ( ptr != NULL ){
+        free(ptr);
+    }
+}
+
+void qpy_esim_msg_proc(void *param)
+{
+    if ( param == NULL ){
+        IPA_LOG("NULL");
+        return ;
+    }
+    unsigned int event_id;
+    int result;
+    void *ctx;
+    Helios_esim_event *event_t = (Helios_esim_event *) param;
+    event_id = event_t->event_id;
+    result = event_t->result;
+    ctx = event_t->ctx;
+       if(g_esim_ipa_user_callback)
+       {   
+        int32_t num = 0;
+        mp_obj_t data_list = mp_obj_new_list(0, NULL);
+        mp_obj_list_append(data_list,mp_obj_new_int(event_id));
+        mp_obj_list_append(data_list,mp_obj_new_int(!!result));
+        HELIOS_ESIM_PROFILE_TAG profile_mode;
+        Helios_esim_ipa_cfg_resp resp;
+        Helios_esim_notification_opt opt_mode ;
+        Helios_esim_notification_resp notification_resp;
+        if ( result != 0 ){
+            if ( event_id == HELIOS_ESIM_LPA_AT_PROFILE_RSP ){
+                profile_mode = *(HELIOS_ESIM_PROFILE_TAG *)ctx;
+                mp_obj_list_append(data_list,mp_obj_new_int(profile_mode));
+            }
+        }else{
+
+            switch(event_id){
+                
+                case HELIOS_ESIM_LPA_AT_PROFILE_RSP                 : 
+                    profile_mode = *(HELIOS_ESIM_PROFILE_TAG *)ctx;
+                    mp_obj_list_append(data_list,mp_obj_new_int(profile_mode));
+                    break;
+                case HELIOS_ESIM_LPA_AT_PROFILE_LIST_RSP     :  
+                    qpy_esim_event_deal_profile_list(data_list,(Helios_Esim_Profilelistinfo_Struct*)ctx);
+                    break;
+                case HELIOS_ESIM_LPA_AT_GET_EID_RSP          :  
+                    num += 1;
+                    mp_obj_list_append(data_list,mp_obj_new_str((const char *)ctx,strlen((const char *)ctx)));
+                    break;
+                
+                case HELIOS_ESIM_LPA_AT_NOTIFICATION_LIST_RSP:  
+                    qpy_esim_event_deal_notification_list(data_list,(Helios_Esim_LPA_Notification_list*)ctx);
+                    break;
+
+                case HELIOS_ESIM_LPA_AT_NOTIFICATION_OPT_RSP : 
+                
+                    notification_resp = *(Helios_esim_notification_resp *)ctx;
+                    mp_obj_t  noticification = mp_obj_new_list(0, NULL); 
+                    mp_obj_list_append(noticification,mp_obj_new_int(notification_resp.opt));
+                    mp_obj_list_append(noticification,mp_obj_new_str(notification_resp.rsp_info.data,notification_resp.rsp_info.data_len));
+                    mp_obj_list_append(data_list,noticification);
+                    break;
+
+                case HELIOS_ESIM_LPA_AT_DOWN_OPT_RSP            :  
+                    
+                    if ( ctx != NULL ){
+                        Helios_Esim_uart_download_resp *resp_data = (Helios_Esim_uart_download_resp *)ctx;
+                        mp_obj_list_append(data_list,mp_obj_new_int(resp_data->down_type));
+                        mp_obj_t download_list_buffer = mp_obj_new_list(0, NULL);
+                        mp_obj_list_append(download_list_buffer,mp_obj_new_int(resp_data->data_len));
+                        mp_obj_list_append(download_list_buffer,mp_obj_new_bytes(resp_data->data,resp_data->data_len));
+                        mp_obj_list_append(download_list_buffer,mp_obj_new_int(resp_data->playload_len));
+                        mp_obj_list_append(download_list_buffer,mp_obj_new_bytes(resp_data->playload_info,resp_data->playload_len));
+                        num += 1;  
+                        mp_obj_list_append(data_list,download_list_buffer);
+                    }else{
+                        mp_obj_list_append(data_list,mp_obj_new_int(0));
+                    }
+                    
+                    break; 
+                case HELIOS_ESIM_LPA_PROFILE_TRANS_RSP          :  
+                    if ( ctx != NULL ){
+                        Helios_Esim_uart_download_resp *resp_data = (Helios_Esim_uart_download_resp *)ctx;
+                        mp_obj_list_append(data_list,mp_obj_new_int(resp_data->down_type));
+                        mp_obj_t download_list_buffer = mp_obj_new_list(0, NULL);
+                        mp_obj_list_append(download_list_buffer,mp_obj_new_int(resp_data->data_len));
+                        mp_obj_list_append(download_list_buffer,mp_obj_new_bytes(resp_data->data,resp_data->data_len));
+                        mp_obj_list_append(download_list_buffer,mp_obj_new_int(resp_data->playload_len));
+                        mp_obj_list_append(download_list_buffer,mp_obj_new_bytes(resp_data->playload_info,resp_data->playload_len));
+                        num += 1;  
+                        mp_obj_list_append(data_list,download_list_buffer);
+                    }
+                    break; 
+                
+                case HELIOS_ESIM_LPA_VERSION_RSP                        :  
+                    num += 1;  
+                    mp_obj_list_append(data_list,mp_obj_new_str((const char *)ctx,strlen((const char *)ctx)));
+                    break; 
+                case HELIOS_ESIM_SDK_COMPILE_RSP                        :  
+                    mp_obj_list_append(data_list,mp_obj_new_str((const char *)ctx,strlen((const char *)ctx)));
+                    break; 
+                case HELIOS_ESIM_IPA_VERSION_RSP                        :  
+                    mp_obj_list_append(data_list,mp_obj_new_str((const char *)ctx,strlen((const char *)ctx)));
+                    break; 
+                case HELIOS_ESIM_IPA_EIM_LIST_RSP                   :  
+                    qpy_esim_eim_list(data_list,(Helios_Esim_Eim_list*)ctx);
+                    break;
+                case HELIOS_ESIM_IPA_TIMER_CFG_GET_RSP       :  
+                    resp = *(Helios_esim_ipa_cfg_resp*)ctx;
+                    mp_obj_t resp_list_buffer = mp_obj_new_list(0, NULL);
+                    mp_obj_list_append(resp_list_buffer,mp_obj_new_int(resp.ipa_poll_interval));
+                    mp_obj_list_append(resp_list_buffer,mp_obj_new_int(resp.rollback_interval));
+                    #if 0
+                    mp_obj_list_append(resp_list_buffer,mp_obj_new_bool(resp.auto_sync_flag));
+                    mp_obj_list_append(resp_list_buffer,mp_obj_new_bool(resp.regular_sync_flag));
+                    mp_obj_list_append(resp_list_buffer,mp_obj_new_int(resp.regular_interval));
+                    #endif
+                    mp_obj_list_append(data_list,resp_list_buffer);
+                    break;
+                
+                case HELIOS_ESIM_IPA_FALLBACK_RSP:
+                    break;
+                case HELIOS_ESIM_IPA_FALLBACK_RETURN_RSP:
+                    break;
+                case HELIOS_ESIM_LPA_AT_SET_APN_RSP:
+                    //do nothing
+                    break;
+                case HELIOS_ESIM_LPA_AT_GET_APN_RSP:
+                    mp_obj_list_append(data_list, mp_obj_new_str((const char *)ctx, strlen((const char *)ctx)));
+                    break;
+                case HELIOS_ESIM_LPA_AT_INVALID_RSP          :
+                    //do nothing
+                    break; 
+                case HELIOS_ESIM_LPA_AT_NICKNAME_RSP         :  
+                    //do nothing
+                    break;
+                case HELIOS_ESIM_LPA_PROFILE_INSTALL_RSP        :  
+                    //do nothing
+                    break; 
+                case HELIOS_ESIM_IPA_POLL_SET_RSP                       :  
+                    // do nothing
+                    break; 
+                case HELIOS_ESIM_IPA_EIM_OPT_RSP             :  
+                    //do nothing
+                    break;
+                case HELIOS_ESIM_IPA_EIM_ADD_RSP             :  
+                    //do nothing
+                    break;
+                default:
+                    if ( ctx != NULL)
+                    {
+                        free(ctx);
+                    }
+                    return;
+            }
+        }
+           mp_sched_schedule_ex(g_esim_ipa_user_callback, data_list);
+       }
+    if ( ctx != NULL)
+    {
+        qpy_esim_free_memory(ctx,event_id);
+    }
+}
+
+static void qpy_esim_event_handler(uint8_t sim_id, unsigned int event_id,int result, void *ctx){
+
+    Helios_esim_event *event_t = NULL;
+    void * ctx_data = NULL;
+    if ( ctx == NULL ){
+        IPA_LOG("1 \n");
+    }
+    switch(event_id){
+        case HELIOS_ESIM_LPA_AT_PROFILE_RSP:
+            if ( ctx == NULL ){
+                break;
+            }
+            ctx_data = (void*)malloc(sizeof(HELIOS_ESIM_PROFILE_TAG));
+            if ( ctx_data != NULL )
+            {
+                memset(ctx_data,0x00,sizeof(HELIOS_ESIM_PROFILE_TAG));
+                memcpy(ctx_data,ctx,sizeof(HELIOS_ESIM_PROFILE_TAG));
+            }
+            break;
+        case HELIOS_ESIM_LPA_AT_PROFILE_LIST_RSP:
+            
+            if ( ctx == NULL ){
+                break;
+            }
+            ctx_data = (void*)malloc(sizeof(Helios_Esim_Profilelistinfo_Struct));
+            if ( ctx_data !=NULL && ctx != NULL ){
+                memset(ctx_data,0x00,sizeof(Helios_Esim_Profilelistinfo_Struct));
+                memcpy(ctx_data,ctx,sizeof(Helios_Esim_Profilelistinfo_Struct));
+            }
+            break;
+        case HELIOS_ESIM_LPA_AT_NOTIFICATION_LIST_RSP:
+            if ( ctx == NULL ){
+                break;
+            }
+            ctx_data = (void*)malloc(sizeof(Helios_Esim_LPA_Notification_list));
+            if ( ctx_data != NULL )
+            {
+                memset(ctx_data,0x00,sizeof(Helios_Esim_LPA_Notification_list));
+                memcpy(ctx_data,ctx,sizeof(Helios_Esim_LPA_Notification_list));
+            }
+            break;
+        case HELIOS_ESIM_LPA_AT_DOWN_OPT_RSP:
+            if ( ctx == NULL ){
+                break;
+            }
+            ctx_data = (Helios_Esim_uart_download_resp*)malloc(sizeof(Helios_Esim_uart_download_resp));
+            if ( ctx_data != NULL )
+            {
+                Helios_Esim_uart_download_resp * data_ptr = (Helios_Esim_uart_download_resp*)ctx_data;
+                memset(data_ptr,0x00,sizeof(Helios_Esim_uart_download_resp));
+                memcpy(data_ptr,ctx,sizeof(Helios_Esim_uart_download_resp));
+                data_ptr->playload_len = ((Helios_Esim_uart_download_resp *)ctx)->playload_len;
+                if ( data_ptr->playload_len != 0 ){
+                    data_ptr->playload_info = malloc(data_ptr->playload_len);
+                    memcpy(data_ptr->playload_info,((Helios_Esim_uart_download_resp *)ctx)->playload_info,data_ptr->playload_len);
+                }else{
+                    data_ptr->playload_info = NULL;
+                }
+            }
+            break;
+
+        case HELIOS_ESIM_LPA_PROFILE_TRANS_RSP:
+            if ( ctx == NULL ){
+                break;
+            }
+            ctx_data = (void*)malloc(sizeof(Helios_Esim_uart_download_resp));
+            if ( ctx_data != NULL )
+            {
+                Helios_Esim_uart_download_resp * data_ptr = (Helios_Esim_uart_download_resp*)ctx_data;
+                memset(data_ptr,0x00,sizeof(Helios_Esim_uart_download_resp));
+                memcpy(data_ptr,ctx,sizeof(Helios_Esim_uart_download_resp));
+                data_ptr->playload_len = ((Helios_Esim_uart_download_resp *)ctx)->playload_len;
+                if ( data_ptr->playload_len != 0 ){
+                    data_ptr->playload_info = malloc(data_ptr->playload_len);
+                    memcpy(data_ptr->playload_info,((Helios_Esim_uart_download_resp *)ctx)->playload_info,data_ptr->playload_len);
+                }else{
+                    data_ptr->playload_info = NULL;
+                }
+            }
+            break;
+        case HELIOS_ESIM_LPA_AT_NOTIFICATION_OPT_RSP:
+            if ( ctx == NULL ){
+                break;
+            }
+            ctx_data = (void*)malloc(sizeof(Helios_esim_notification_resp));
+            if ( ctx_data != NULL )
+            {
+                memset(ctx_data,0x00,sizeof(Helios_esim_notification_resp));
+                memcpy(ctx_data,ctx,sizeof(Helios_esim_notification_resp));
+            }
+            break;
+        case HELIOS_ESIM_LPA_AT_SET_APN_RSP:
+        case HELIOS_ESIM_LPA_AT_GET_APN_RSP:
+        case HELIOS_ESIM_LPA_AT_GET_EID_RSP:
+        case HELIOS_ESIM_SDK_COMPILE_RSP:
+        case HELIOS_ESIM_IPA_VERSION_RSP:
+        case HELIOS_ESIM_LPA_VERSION_RSP:
+            if ( ctx == NULL ){
+                break;
+            }
+            ctx_data = (void*)malloc(strlen((const char *)ctx)+1);
+            if ( ctx_data != NULL )
+            {
+                memset(ctx_data,0x00,strlen((const char *)ctx)+1);
+                memcpy(ctx_data,ctx,strlen((const char *)ctx)+1);
+            }
+            break;
+
+        case HELIOS_ESIM_IPA_EIM_LIST_RSP:
+            if ( ctx == NULL ){
+                break;
+            }
+            ctx_data = (void*)malloc(sizeof(Helios_Esim_Eim_list));
+            if ( ctx_data != NULL )
+            {
+                memset(ctx_data,0x00,sizeof(Helios_Esim_Eim_list));
+                memcpy(ctx_data,ctx,sizeof(Helios_Esim_Eim_list));
+            }
+            break;
+
+        case HELIOS_ESIM_IPA_TIMER_CFG_GET_RSP:
+            if ( ctx == NULL ){
+                break;
+            }
+            ctx_data = (void*)malloc(sizeof(Helios_esim_ipa_cfg_resp));
+            if ( ctx_data != NULL )
+            {
+                memset(ctx_data,0x00,sizeof(Helios_esim_ipa_cfg_resp));
+                memcpy(ctx_data,ctx,sizeof(Helios_esim_ipa_cfg_resp));
+            }
+            break;
+        default:
+            break;
+    }
+    event_t = (Helios_esim_event *) malloc(sizeof(Helios_esim_event));
+    if ( event_t != NULL ){
+        event_t->sim_id     = sim_id;
+        event_t->event_id   = event_id;
+        event_t->result     = result;
+        event_t->ctx        = ctx_data;
+        qpy_send_msg_to_callback_deal_thread(CALLBACK_TYPE_ID_ESIM_IPA, event_t);
+    }
+}
+
+STATIC mp_obj_t qpy_esim_add_event_handler(mp_obj_t handler)
+{
+    static c_callback_t cb = {0};
+    memset((void*)&cb, 0, sizeof(c_callback_t));
+    g_esim_ipa_user_callback = &cb;
+    mp_sched_schedule_callback_register(g_esim_ipa_user_callback, handler);
+
+       Helios_Esim_Add_Event_Handler(qpy_esim_event_handler);
+       
+       return mp_obj_new_int(0);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_add_event_handler_obj, qpy_esim_add_event_handler);
+STATIC mp_obj_t qpy_esim_init(const mp_obj_t list_mode){
+
+    if ( !mp_obj_is_int(list_mode) ){
+        return mp_obj_new_int(-1);
+    }
+    Helios_Esim_Mode esim_mode = (Helios_Esim_Mode) mp_obj_get_int(list_mode);
+    MP_THREAD_GIL_EXIT();
+    int ret  = Helios_Esim_init(esim_mode);
+    MP_THREAD_GIL_ENTER();
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_init_obj, qpy_esim_init);
+
+STATIC mp_obj_t qpy_esim_reinit(const mp_obj_t list_mode){
+
+    if ( !mp_obj_is_int(list_mode) ){
+        return mp_obj_new_int(-1);
+    }
+    Helios_Esim_Mode esim_mode = (Helios_Esim_Mode) mp_obj_get_int(list_mode);
+    MP_THREAD_GIL_EXIT();
+    Helios_Esim_deinit();
+    Helios_sleep(1);
+    int ret  = Helios_Esim_init(esim_mode);
+    Helios_Esim_Add_Event_Handler(qpy_esim_event_handler);
+    MP_THREAD_GIL_ENTER();
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_reinit_obj, qpy_esim_reinit);
+
+
+/*=============================================================================*/
+/* FUNCTION: qpy_esim_get_eid                                                  */
+/*=============================================================================*/
+/*!@brief: Get the euicc id of the eSIM card
+ *     
+ * @return:
+ *     if get successfully, return the eid
+ *    -1       -       error
+ */
+/*=============================================================================*/
+STATIC mp_obj_t qpy_esim_get_eid(void)
+{
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_Esim_Get_Eid();
+    MP_THREAD_GIL_ENTER();
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_esim_get_eid_obj, qpy_esim_get_eid);
+
+STATIC mp_obj_t qpy_esim_get_profiles_info(const mp_obj_t list_mode)
+{
+       int listmode = mp_obj_get_int(list_mode);
+    if (listmode !=0 && listmode != 1)
+    {
+        mp_raise_ValueError("invalid value, listmode must be 0/1.");
+    }
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_Esim_Get_Profiles_Info(listmode);
+    MP_THREAD_GIL_ENTER();
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_get_profiles_info_obj, qpy_esim_get_profiles_info);
+
+STATIC mp_obj_t qpy_esim_profile_handle( HELIOS_ESIM_PROFILE_TAG profile_tag, const mp_obj_t iccid)
+{
+    int ret = 0;
+       HELIOS_ESIM_PROFILE_TAG pro_tag = profile_tag;
+    mp_buffer_info_t iccidinfo = {0};
+       mp_get_buffer_raise(iccid, &iccidinfo, MP_BUFFER_READ);
+    if (iccidinfo.len > 20)
+       {
+               mp_raise_ValueError("invalid value, the length of iccid should be no more than 20 bytes.");
+       }
+    
+    MP_THREAD_GIL_EXIT();
+       ret = Helios_Esim_LPA_Profile_Handle(pro_tag, iccidinfo.buf);
+    MP_THREAD_GIL_ENTER();
+       return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t qpy_esim_enable_profile_handle(const mp_obj_t iccid){
+    return qpy_esim_profile_handle(HELIOS_ESIM_ENABLE_PROFILE,iccid);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_enable_profile_handle_obj, qpy_esim_enable_profile_handle);
+
+STATIC mp_obj_t qpy_esim_disable_profile_handle(const mp_obj_t iccid){
+    return qpy_esim_profile_handle(HELIOS_ESIM_DISABLE_PROFILE,iccid);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_disable_profile_handle_obj, qpy_esim_disable_profile_handle);
+
+STATIC mp_obj_t qpy_esim_uninstall_profile_handle(const mp_obj_t iccid){
+    return qpy_esim_profile_handle(HELIOS_ESIM_DELETE_PROFILE,iccid);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_uninstall_profile_handle_obj, qpy_esim_uninstall_profile_handle);
+
+STATIC mp_obj_t qpy_esim_lpa_set_nickname_handle(const mp_obj_t iccid, const mp_obj_t nickname)
+{
+    int ret = 0;
+    mp_buffer_info_t iccidinfo = {0};
+    mp_buffer_info_t nickname_info = {0};
+       mp_get_buffer_raise(iccid, &iccidinfo, MP_BUFFER_READ);
+    mp_get_buffer_raise(nickname, &nickname_info, MP_BUFFER_READ);
+    if (iccidinfo.len > 20)
+       {
+               mp_raise_ValueError("invalid value, the length of iccid should be no more than 20 bytes.");
+       }
+    MP_THREAD_GIL_EXIT();
+       ret = Helios_Esim_LPA_Set_Nickname(iccidinfo.buf, nickname_info.buf);
+    MP_THREAD_GIL_ENTER();
+       return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_esim_lpa_set_nickname_obj, qpy_esim_lpa_set_nickname_handle);
+
+STATIC mp_obj_t qpy_esim_lpa_profile_download_handle(const mp_obj_t download_in, const mp_obj_t activationCode,const mp_obj_t confirmationCode)
+{
+    int ret = 0;
+       Helios_esim_lpa_profile_down_opt opt_mode = (Helios_esim_lpa_profile_down_opt)mp_obj_get_int(download_in);
+    
+    mp_buffer_info_t activationCode_in = {0};
+    mp_buffer_info_t confirmationCode_in = {0};
+       mp_get_buffer_raise( activationCode,&activationCode_in, MP_BUFFER_READ);
+    mp_get_buffer_raise( confirmationCode,&confirmationCode_in, MP_BUFFER_READ);
+    
+    MP_THREAD_GIL_EXIT();
+       ret = Helios_Esim_LPA_Profile_Ota(opt_mode,activationCode_in.buf, confirmationCode_in.buf);
+    MP_THREAD_GIL_ENTER();
+       return mp_obj_new_int(ret);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_esim_lpa_profile_download_obj, qpy_esim_lpa_profile_download_handle);
+
+STATIC mp_obj_t qpy_esim_lpa_get_version_handle(void)
+{
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_Esim_LPA_Get_Version();
+    MP_THREAD_GIL_ENTER();
+       return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_esim_lpa_get_version_obj, qpy_esim_lpa_get_version_handle);
+
+STATIC mp_obj_t qpy_esim_lpa_get_compile_time_handle(void)
+{
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_Esim_LPA_Get_CompileTime();
+    MP_THREAD_GIL_ENTER();
+       return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_esim_lpa_get_compile_time_obj, qpy_esim_lpa_get_compile_time_handle);
+
+STATIC mp_obj_t qpy_esim_lpa_profile_trans_handle(size_t n_args, const mp_obj_t *args){
+    uint32_t  total_len = mp_obj_get_int(args[0]);
+    bool      status    = (args[1] == mp_const_true)?1:0;
+    uint8_t   seq       = mp_obj_get_int(args[2]);
+    uint32_t   data_len  = mp_obj_get_int(args[3]);
+    mp_buffer_info_t data = {0};
+    mp_get_buffer_raise(args[4], &data, MP_BUFFER_READ);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_Esim_LPA_Profile_Trans(total_len,status,seq,data_len,data.buf);
+    MP_THREAD_GIL_ENTER();
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qpy_esim_lpa_profile_trans_handle_obj, 5, 5, qpy_esim_lpa_profile_trans_handle);
+
+
+STATIC mp_obj_t qpy_esim_notification_list_handle(const mp_obj_t list_mode)
+{
+       Helios_Esim_Notification_Type type = (Helios_Esim_Notification_Type)mp_obj_get_int(list_mode);
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_Esim_LPA_Get_Notification_List(type);
+    MP_THREAD_GIL_ENTER();
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_notification_list_obj, qpy_esim_notification_list_handle);
+
+
+STATIC mp_obj_t qpy_esim_lpa_notification_hdlr_handle( Helios_esim_notification_opt opt_mode, mp_obj_t seq_num)
+{
+    int ret = 0;
+       Helios_esim_notification_opt opt_modem_in = opt_mode;
+    uint32_t seq_num_in = (uint32_t)mp_obj_get_int(seq_num);
+    
+    MP_THREAD_GIL_EXIT();
+       ret = Helios_Esim_LPA_Notification_hdlr(opt_modem_in, seq_num_in);
+    MP_THREAD_GIL_ENTER();
+       return mp_obj_new_int(ret);
+}
+
+
+STATIC mp_obj_t qpy_esim_lpa_notification_get_handle( mp_obj_t seq_num)
+{
+       return qpy_esim_lpa_notification_hdlr_handle(HELIOS_ESIM_AT_NOTIFICATION_GET_OPT,seq_num);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_lpa_notification_get_obj, qpy_esim_lpa_notification_get_handle);
+
+STATIC mp_obj_t qpy_esim_lpa_notification_delete_handle( mp_obj_t seq_num)
+{
+       return qpy_esim_lpa_notification_hdlr_handle(HELIOS_ESIM_AT_NOTIFICATION_DELETE_OPT,seq_num);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_lpa_notification_delete_obj, qpy_esim_lpa_notification_delete_handle);
+
+STATIC mp_obj_t qpy_esim_lpa_notification_report_handle( mp_obj_t seq_num)
+{
+       return qpy_esim_lpa_notification_hdlr_handle(HELIOS_ESIM_AT_NOTIFICATION_REPORT_OPT,seq_num);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_lpa_notification_report_obj, qpy_esim_lpa_notification_report_handle);
+
+STATIC mp_obj_t qpy_esim_ipa_poll_interval_set_handle(const mp_obj_t second)
+{
+    int ret = 0;
+    int sec = (uint32_t)mp_obj_get_int(second);
+    MP_THREAD_GIL_EXIT();
+       ret = Helios_Esim_IPA_Poll_Interval_Set(sec);
+    MP_THREAD_GIL_ENTER();
+       return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_ipa_poll_interval_set_obj, qpy_esim_ipa_poll_interval_set_handle);
+
+
+STATIC mp_obj_t qpy_esim_ipa_eim_list_handle(void)
+{
+    int ret = 0;
+    MP_THREAD_GIL_EXIT();
+       ret = Helios_Esim_IPA_Eim_List();
+    MP_THREAD_GIL_ENTER();
+       return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_esim_ipa_eim_list_obj, qpy_esim_ipa_eim_list_handle);
+
+STATIC mp_obj_t qpy_esim_ipa_eim_info_opt_handle(const mp_obj_t eim_id_in,const mp_obj_t eim_domain_in, Helios_esim_eim_opt mode_in)
+{
+    int ret = 0;
+    mp_buffer_info_t eim_id = {0};
+    mp_buffer_info_t eim_domain = {0};
+    Helios_esim_eim_opt mode  = mode_in;
+    mp_get_buffer_raise(eim_id_in, &eim_id, MP_BUFFER_READ);
+    mp_get_buffer_raise(eim_domain_in,&eim_domain,  MP_BUFFER_READ);
+    
+    MP_THREAD_GIL_EXIT();
+       ret = Helios_Esim_IPA_Eim_Info_Opt(eim_id.buf,eim_domain.buf,mode);
+    MP_THREAD_GIL_ENTER();
+    IPA_LOG("[ESIM] qpy_esim_ipa_eim_info_opt_handle(%d)=%d : [%s][%s]",mode,ret,eim_id.buf,eim_domain.buf);
+       return mp_obj_new_int(ret);
+}
+
+STATIC mp_obj_t qpy_esim_ipa_eim_info_update_handle(const mp_obj_t eim_id_in,const mp_obj_t eim_domain_in)
+{
+       return qpy_esim_ipa_eim_info_opt_handle(eim_id_in,eim_domain_in,HELIOS_ESIM_EIM_UPDATE);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_esim_ipa_eim_info_update_obj, qpy_esim_ipa_eim_info_update_handle);
+
+STATIC mp_obj_t qpy_esim_ipa_eim_info_delete_handle(const mp_obj_t eim_id_in,const mp_obj_t eim_domain_in)
+{
+    
+       return qpy_esim_ipa_eim_info_opt_handle(eim_id_in,eim_domain_in,HELIOS_ESIM_EIM_DELETE);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_esim_ipa_eim_info_delete_obj, qpy_esim_ipa_eim_info_delete_handle);
+
+STATIC mp_obj_t qpy_esim_ipa_eim_info_add_handle(const mp_obj_t eim_id_in,const mp_obj_t eim_domain_in)
+{
+       return qpy_esim_ipa_eim_info_opt_handle(eim_id_in,eim_domain_in,HELIOS_ESIM_EIM_ADD);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_esim_ipa_eim_info_add_obj, qpy_esim_ipa_eim_info_add_handle);
+
+STATIC mp_obj_t qpy_esim_ipa_get_cfg_timer_handle(void)
+{
+    int ret = 0;
+    MP_THREAD_GIL_EXIT();
+       ret = Helios_Esim_IPA_Timer_Cfg_Get();
+    MP_THREAD_GIL_ENTER();
+       return mp_obj_new_int(ret);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_esim_ipa_get_cfg_timer_obj, qpy_esim_ipa_get_cfg_timer_handle);
+
+#ifdef ESIM_APN
+STATIC mp_obj_t qpy_esim_lpa_get_apn(void)
+{
+    MP_THREAD_GIL_EXIT();
+    int ret = Helios_Esim_LPA_Get_Apn();
+    MP_THREAD_GIL_ENTER();
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_esim_lpa_get_apn_obj, qpy_esim_lpa_get_apn);
+
+STATIC mp_obj_t qpy_esim_lpa_set_apn(const mp_obj_t apn)
+{
+    int ret = 0;
+    mp_buffer_info_t apn_info = {0};
+    mp_get_buffer_raise(apn, &apn_info, MP_BUFFER_READ);
+    if (apn_info.len > 10)
+    {
+        mp_raise_ValueError("invalid value, the length of apn should be no more than 10 bytes.");
+    }
+    MP_THREAD_GIL_EXIT();
+    ret = Helios_Esim_LPA_Set_Apn(apn_info.buf);
+    MP_THREAD_GIL_ENTER();
+    return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_esim_lpa_set_apn_obj, qpy_esim_lpa_set_apn);
+#endif
+
+STATIC mp_obj_t qpy_esim_deinit(void)
+{
+       Helios_Esim_Add_Event_Handler(NULL);
+    g_esim_ipa_user_callback = NULL;
+    Helios_Esim_deinit(0);
+       return mp_obj_new_int(0);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_esim_deinit_obj, qpy_esim_deinit);
+
+STATIC const mp_rom_map_elem_t mp_module_esim_globals_table[] = {
+    
+    { MP_ROM_QSTR(MP_QSTR___name__),                   MP_ROM_QSTR(MP_QSTR_esim)                                },
+    { MP_ROM_QSTR(MP_QSTR_init),                           MP_ROM_PTR(&qpy_esim_init_obj)                   },
+    { MP_ROM_QSTR(MP_QSTR_reinit),                         MP_ROM_PTR(&qpy_esim_reinit_obj)                 },
+    { MP_ROM_QSTR(MP_QSTR_get_eid),                    MP_ROM_PTR(&qpy_esim_get_eid_obj)                    },
+       { MP_ROM_QSTR(MP_QSTR_setCallback),             MP_ROM_PTR(&qpy_esim_add_event_handler_obj)  },
+
+    //profile information api
+    { MP_ROM_QSTR(MP_QSTR_lpa_get_profile),         MP_ROM_PTR(&qpy_esim_get_profiles_info_obj)  },
+    { MP_ROM_QSTR(MP_QSTR_lpa_enable_profile),      MP_ROM_PTR(&qpy_esim_enable_profile_handle_obj)     },
+    { MP_ROM_QSTR(MP_QSTR_lpa_disable_profile),     MP_ROM_PTR(&qpy_esim_disable_profile_handle_obj)    },
+    { MP_ROM_QSTR(MP_QSTR_lpa_uninstall_profile),   MP_ROM_PTR(&qpy_esim_uninstall_profile_handle_obj)          },
+    { MP_ROM_QSTR(MP_QSTR_lpa_install_profile),     MP_ROM_PTR(&qpy_esim_lpa_profile_download_obj)},
+
+    { MP_ROM_QSTR(MP_QSTR_lpa_set_nickname),        MP_ROM_PTR(&qpy_esim_lpa_set_nickname_obj)          },
+    { MP_ROM_QSTR(MP_QSTR_get_version),             MP_ROM_PTR(&qpy_esim_lpa_get_version_obj)},
+    { MP_ROM_QSTR(MP_QSTR_get_compile_time),        MP_ROM_PTR(&qpy_esim_lpa_get_compile_time_obj)},
+    { MP_ROM_QSTR(MP_QSTR_lpa_profile_trans),       MP_ROM_PTR(&qpy_esim_lpa_profile_trans_handle_obj)},
+    
+    { MP_ROM_QSTR(MP_QSTR_lpa_query_notification),  MP_ROM_PTR(&qpy_esim_notification_list_obj)},
+
+    { MP_ROM_QSTR(MP_QSTR_lpa_get_notification),    MP_ROM_PTR(&qpy_esim_lpa_notification_get_obj)},
+    { MP_ROM_QSTR(MP_QSTR_lpa_delete_notification), MP_ROM_PTR(&qpy_esim_lpa_notification_delete_obj)},
+    { MP_ROM_QSTR(MP_QSTR_lpa_report_notification), MP_ROM_PTR(&qpy_esim_lpa_notification_report_obj)},
+    
+    { MP_ROM_QSTR(MP_QSTR_ipa_set_poll_timer),      MP_ROM_PTR(&qpy_esim_ipa_poll_interval_set_obj)},
+    { MP_ROM_QSTR(MP_QSTR_ipa_get_timer),           MP_ROM_PTR(&qpy_esim_ipa_get_cfg_timer_obj)},
+
+    { MP_ROM_QSTR(MP_QSTR_ipa_get_eim),             MP_ROM_PTR(&qpy_esim_ipa_eim_list_obj)},
+    { MP_ROM_QSTR(MP_QSTR_ipa_update_eim),          MP_ROM_PTR(&qpy_esim_ipa_eim_info_update_obj)},
+    { MP_ROM_QSTR(MP_QSTR_ipa_delete_eim),          MP_ROM_PTR(&qpy_esim_ipa_eim_info_delete_obj)},
+    { MP_ROM_QSTR(MP_QSTR_ipa_add_eim),             MP_ROM_PTR(&qpy_esim_ipa_eim_info_add_obj)},
+
+#ifdef ESIM_APN
+    { MP_ROM_QSTR(MP_QSTR_lpa_get_apn),             MP_ROM_PTR(&qpy_esim_lpa_get_apn_obj)},
+    { MP_ROM_QSTR(MP_QSTR_lpa_set_apn),             MP_ROM_PTR(&qpy_esim_lpa_set_apn_obj)},
+#endif
+
+       { MP_ROM_QSTR(MP_QSTR_deinit),                  MP_ROM_PTR(&qpy_esim_deinit_obj)},
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_esim_globals, mp_module_esim_globals_table);
+
+const mp_obj_module_t mp_module_esim = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t *)&mp_module_esim_globals,
+};
+
+#endif
+
+
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/tp_ft6x36.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/tp_ft6x36.c
new file mode 100644 (file)
index 0000000..897f369
--- /dev/null
@@ -0,0 +1,791 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**************************************************************************
+ @file tp_ft6x36.c
+ @brief        touchpad ft6x36 module interface package.
+
+ DESCRIPTION
+ This module provide the touchpad ft6x36 interface of micropython.
+
+ INITIALIZATION AND SEQUENCING REQUIREMENTS
+
+
+ ===========================================================================
+ Copyright (c) 2018 Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ Quectel Wireless Solution Proprietary and Confidential.
+ ===========================================================================
+
+                                               EDIT HISTORY FOR FILE
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+WHEN           WHO                     WHAT,WHERE,WHY
+----------  ---------   ---------------------------------------------------
+12/20/2023  felix.ye   Create.
+**************************************************************************/
+
+//////////////////////////////////////////////////////////////////////////////
+// Includes
+//////////////////////////////////////////////////////////////////////////////
+#include <stdio.h>
+#include "runtime.h"
+#include <stdlib.h>
+#include <math.h>
+#include "mphalport.h"
+#include "compile.h"
+#include "repl.h"
+#include "mperrno.h"
+#include "binary.h"
+
+#include <string.h>
+
+#if MICROPY_QPY_TP_FT6X36
+
+
+#include "helios_gpio.h"
+#include "helios_iic.h"
+#include "helios_lcd.h"
+#include "helios_fs.h"
+#include "helios_pin.h"
+
+#ifdef CONFIG_LVGL
+#include "lvgl.h"
+#define TP_STATE_DETECTION
+#endif
+
+#ifdef TP_STATE_DETECTION
+#include "callbackdeal.h"
+#endif
+
+#include "helios_debug.h"
+#define FT6X36_LOG(msg, ...)      custom_log("FT6336", msg, ##__VA_ARGS__)
+
+// Defines
+//////////////////////////////////////////////////////////////////////////////
+
+// FT6X36 寄存器定义
+#define FT6X36_ADDR                                            0x38
+
+#define FT6X36_REG_DEVICE_MODE                 0x00
+#define FT6X36_REG_GESTURE_ID                  0x01
+#define FT6X36_REG_NUM_TOUCHES                 0x02
+#define FT6X36_REG_P1_XH                               0x03
+#define FT6X36_REG_P1_XL                               0x04
+#define FT6X36_REG_P1_YH                               0x05
+#define FT6X36_REG_P1_YL                               0x06
+#define FT6X36_REG_P1_WEIGHT                   0x07
+#define FT6X36_REG_P1_MISC                             0x08
+#define FT6X36_REG_P2_XH                               0x09
+#define FT6X36_REG_P2_XL                               0x0A
+#define FT6X36_REG_P2_YH                               0x0B
+#define FT6X36_REG_P2_YL                               0x0C
+#define FT6X36_REG_P2_WEIGHT                   0x0D
+#define FT6X36_REG_P2_MISC                             0x0E
+#define FT6X36_REG_THRESHHOLD                  0x80
+#define FT6X36_REG_FILTER_COEF                 0x85
+#define FT6X36_REG_CTRL                                        0x86
+#define FT6X36_REG_TIME_ENTER_MONITOR  0x87
+#define FT6X36_REG_TOUCHRATE_ACTIVE            0x88
+#define FT6X36_REG_TOUCHRATE_MONITOR   0x89 // value in ms
+#define FT6X36_REG_RADIAN_VALUE                        0x91
+#define FT6X36_REG_OFFSET_LEFT_RIGHT   0x92
+#define FT6X36_REG_OFFSET_UP_DOWN              0x93
+#define FT6X36_REG_DISTANCE_LEFT_RIGHT 0x94
+#define FT6X36_REG_DISTANCE_UP_DOWN            0x95
+#define FT6X36_REG_DISTANCE_ZOOM               0x96
+#define FT6X36_REG_LIB_VERSION_H               0xA1
+#define FT6X36_REG_LIB_VERSION_L               0xA2
+#define FT6X36_REG_CHIPID                              0xA3
+#define FT6X36_REG_INTERRUPT_MODE              0xA4
+#define FT6X36_REG_POWER_MODE                  0xA5
+#define FT6X36_REG_FIRMWARE_VERSION            0xA6
+#define FT6X36_REG_PANEL_ID                            0xA8
+#define FT6X36_REG_STATE                               0xBC
+
+#define FT6X36_PMODE_ACTIVE                            0x00
+#define FT6X36_PMODE_MONITOR                   0x01
+#define FT6X36_PMODE_STANDBY                   0x02
+#define FT6X36_PMODE_HIBERNATE                 0x03
+
+#define FT6X36_VENDID                                  0x11
+#define FT6206_CHIPID                                  0x06
+#define FT6236_CHIPID                                  0x36
+#define FT6336_CHIPID                                  0x64
+
+#define FT6X36_DEFAULT_THRESHOLD               22
+
+#define TP_PRES_DOWN 0x80              //触屏被按下
+
+
+#define FT6X36_AVG 2
+#define PTR_OBJ(ptr_global) ptr_global ## _obj
+#define TRUE 1
+#define FALSE 0
+
+#define GT_INT Helios_GPIO_GetLevel(g_ft6x36->irq)
+
+typedef struct mp_ptr_t
+{
+    mp_obj_base_t base;
+    void *ptr;
+} mp_ptr_t;
+
+#define DEFINE_PTR_OBJ_TYPE(ptr_obj_type, ptr_type_qstr)\
+STATIC const mp_obj_type_t ptr_obj_type = {\
+    { &mp_type_type },\
+    .name = ptr_type_qstr,\
+    .buffer_p = { .get_buffer = mp_ptr_get_buffer }\
+}
+
+
+#define DEFINE_PTR_OBJ(ptr_global)\
+DEFINE_PTR_OBJ_TYPE(ptr_global ## _type, MP_QSTR_ ## ptr_global);\
+STATIC const mp_ptr_t PTR_OBJ(ptr_global) = {\
+    { &ptr_global ## _type },\
+    &ptr_global\
+}
+
+STATIC mp_int_t mp_ptr_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags)
+{
+    mp_ptr_t *self = MP_OBJ_TO_PTR(self_in);
+
+    if (flags & MP_BUFFER_WRITE) {
+        // read-only ptr
+        //return 1;
+    }
+
+    bufinfo->buf = &self->ptr;
+    bufinfo->len = sizeof(self->ptr);
+    bufinfo->typecode = BYTEARRAY_TYPECODE;
+    return 0;
+}
+
+typedef struct _ft6x36_obj_t
+{
+    mp_obj_base_t base;
+
+    uint8_t i2c_no;
+       uint8_t i2c_mode;
+    uint8_t irq;
+       uint8_t reset;
+       uint8_t x_reverse;
+       uint8_t y_reverse;
+       uint32_t sleep_us;
+
+    int16_t x_min;
+    int16_t y_min;
+    int16_t x_max;
+    int16_t y_max;
+    bool x_inv;
+    bool y_inv;    
+    bool xy_swap;
+       
+
+    int16_t avg_buf_x[FT6X36_AVG];
+    int16_t avg_buf_y[FT6X36_AVG];
+    uint8_t avg_last;
+       int16_t width;
+       int16_t height;
+       int16_t addr;
+
+#ifdef TP_STATE_DETECTION
+       c_callback_t cb;
+#endif
+
+} ft6x36_obj_t;
+
+STATIC ft6x36_obj_t *g_ft6x36 = NULL;
+
+static Helios_Mutex_t gt_mutex;
+
+static uint8_t ft6x36Init = FALSE;//ft6x36已初始化标志
+static uint8_t ft6x36_is_sleep = FALSE;
+static int ft6336_y_offset = 0;
+
+//触摸点相关数据结构体定义
+typedef struct
+{
+       uint8_t TouchSta; //触摸情况,b7:按下1/松开0; b6:0没有按键按下/1有按键按下;bit5:保留;bit4-bit0触摸点按下有效标志,有效为1,分别对应触摸点5-1;
+       uint16_t x[2];   //支持5点触摸,需要使用5组坐标存储触摸点数据
+       uint16_t y[2];
+
+} TouchPointRefTypeDef1;
+static TouchPointRefTypeDef1 TPR_Structure;
+
+#ifdef TP_STATE_DETECTION
+#define TP_CALLBACK_OP(tp_state)     do{                                                                                                                                                                  \
+                                                                                       if(g_ft6x36->cb.cb != NULL) {                                                  \
+                                               st_CallBack_TP *tp_cb = malloc(sizeof(st_CallBack_TP));                    \
+                                               if(NULL != tp_cb) {                                                        \
+                                                       tp_cb->callback = g_ft6x36->cb;                                        \
+                                                       tp_cb->state = tp_state;                                               \
+                                                       qpy_send_msg_to_callback_deal_thread(CALLBACK_TYPE_ID_TP, tp_cb);      \
+                                                       }                                                                                                                                                  \
+                                                                                       }                                                                              \
+                                        }while(0)
+#endif
+
+//
+void FT6X36_RD_Reg(uint8_t reg,uint8_t *buf,uint8_t len)
+{
+    uint8_t reg_addr = reg;
+       HELIOS_I2C_Read((Helios_I2CEnum)g_ft6x36->i2c_no, g_ft6x36->addr, &reg_addr, 1, (void*)buf, len, 0);
+} 
+
+uint8_t FT6X36_WR_Reg(uint8_t reg,uint8_t *buf,uint8_t len)
+{
+    uint8_t reg_addr = reg;
+       FT6X36_LOG("ft6x36 iic write reg = %d, buf is %d\n", reg_addr, *buf);
+       return HELIOS_I2C_Write((Helios_I2CEnum)g_ft6x36->i2c_no, g_ft6x36->addr, &reg_addr, 1, buf, len);
+}
+
+STATIC mp_obj_t mp_activate_FT6X36(mp_obj_t self_in)
+{
+    ft6x36_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    g_ft6x36 = self;
+    return mp_const_none;
+}
+
+STATIC mp_obj_t FT6X36_make_new(const mp_obj_type_t *type,
+                               size_t n_args,
+                               size_t n_kw,
+                               const mp_obj_t *all_args)
+{
+    enum{
+        ARG_i2c_no,
+        ARG_i2c_mode,
+        ARG_irq,
+               ARG_x_reverse,
+               ARG_y_reverse,
+        ARG_reset,
+
+        ARG_x_inv,
+        ARG_y_inv,
+        ARG_xy_swap,
+               
+
+               ARG_width,
+               ARG_height,
+
+               ARG_addr,
+    };
+
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_i2c_no, MP_ARG_INT, {.u_int = 1}},
+        { MP_QSTR_i2c_mode, MP_ARG_INT, {.u_int = 0}},
+        { MP_QSTR_irq, MP_ARG_INT, {.u_int = 2}},
+               { MP_QSTR_x_reverse, MP_ARG_INT, {.u_int = 0}},
+               { MP_QSTR_y_reverse, MP_ARG_INT, {.u_int = 0}},
+        { MP_QSTR_reset, MP_ARG_INT, {.u_int = 4}},
+
+        { MP_QSTR_x_inv, MP_ARG_BOOL, {.u_obj = mp_const_true}},
+        { MP_QSTR_y_inv, MP_ARG_BOOL, {.u_obj = mp_const_true}},
+        { MP_QSTR_xy_swap, MP_ARG_BOOL, {.u_obj = mp_const_false}},
+        { MP_QSTR_width, MP_ARG_INT, {.u_int = 240}},
+        { MP_QSTR_height, MP_ARG_INT, {.u_int = 240}},
+               { MP_QSTR_addr, MP_ARG_INT, {.u_int = FT6X36_ADDR}},
+
+    };
+
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+    ft6x36_obj_t *self = m_new_obj(ft6x36_obj_t);
+    self->base.type = type;
+
+    self->i2c_no = args[ARG_i2c_no].u_int;
+       self->i2c_mode = args[ARG_i2c_mode].u_int;
+    self->irq = args[ARG_irq].u_int;
+       self->x_reverse = args[ARG_x_reverse].u_int;
+       self->y_reverse = args[ARG_y_reverse].u_int;
+       self->reset = args[ARG_reset].u_int;
+       self->width = args[ARG_width].u_int;
+       self->height = args[ARG_height].u_int;
+       self->addr = args[ARG_addr].u_int;
+
+       #ifdef TP_STATE_DETECTION
+       memset(&(self->cb), 0, sizeof(c_callback_t));
+       #endif
+    return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t mp_FT6X36_init(mp_obj_t self_in);
+STATIC mp_obj_t mp_FT6X36_deinit(mp_obj_t self_in);
+#ifdef CONFIG_LVGL
+STATIC bool FT6X36_read(lv_indev_drv_t * indev_drv, lv_indev_data_t *data);
+#endif
+STATIC mp_obj_t mp_FT6X36_read_xy(mp_obj_t self_in);
+#ifdef TP_STATE_DETECTION
+STATIC mp_obj_t mp_FT6X36_register_usr_cb(mp_obj_t self_in, mp_obj_t callback);
+#endif
+STATIC mp_obj_t mp_FT6X36_suspend(mp_obj_t self_in);
+STATIC mp_obj_t mp_FT6X36_resume(mp_obj_t self_in);
+STATIC mp_obj_t mp_FT6X36_set_y_offset(mp_obj_t self_in, mp_obj_t in_y_offset);
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_init_FT6X36_obj, mp_FT6X36_init);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_deinit_FT6X36_obj, mp_FT6X36_deinit);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_activate_FT6X36_obj, mp_activate_FT6X36);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_readxy_FT6X36_obj, mp_FT6X36_read_xy);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_suspend_FT6X36_obj, mp_FT6X36_suspend);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_resume_FT6X36_obj, mp_FT6X36_resume);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_set_y_offset_FT6X36_obj, mp_FT6X36_set_y_offset);
+
+#ifdef CONFIG_LVGL
+DEFINE_PTR_OBJ(FT6X36_read);
+#endif
+
+#ifdef TP_STATE_DETECTION
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_FT6X36_register_usr_cb_obj, mp_FT6X36_register_usr_cb);
+#endif
+
+STATIC const mp_rom_map_elem_t FT6X36_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mp_init_FT6X36_obj) },
+    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mp_deinit_FT6X36_obj) },
+    { MP_ROM_QSTR(MP_QSTR_activate), MP_ROM_PTR(&mp_activate_FT6X36_obj) },
+       { MP_ROM_QSTR(MP_QSTR_read_xy), MP_ROM_PTR(&mp_readxy_FT6X36_obj) },
+       { MP_ROM_QSTR(MP_QSTR_suspend), MP_ROM_PTR(&mp_suspend_FT6X36_obj) },
+       { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mp_resume_FT6X36_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_y_offset), MP_ROM_PTR(&mp_set_y_offset_FT6X36_obj) },
+#ifdef CONFIG_LVGL
+    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&PTR_OBJ(FT6X36_read)) },
+#endif
+#ifdef TP_STATE_DETECTION
+       { MP_ROM_QSTR(MP_QSTR_set_callback), MP_ROM_PTR(&mp_FT6X36_register_usr_cb_obj) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(FT6X36_locals_dict, FT6X36_locals_dict_table);
+
+const mp_obj_type_t tp_FT6X36_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_FT6X36,
+    .make_new = FT6X36_make_new,
+    .locals_dict = (mp_obj_dict_t*)&FT6X36_locals_dict,
+};
+
+/*
+**函数名:FT6X36_Init
+**功能:初始化FT6X36引脚
+*/
+mp_obj_t mp_FT6X36_init(mp_obj_t self_in)
+{
+
+       int ret;
+    uint8_t temp;
+
+    ft6x36_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_activate_FT6X36(self_in);
+
+       
+       Helios_GPIOInitStruct gpio_struct = {0};
+       gpio_struct.dir = HELIOS_GPIO_INPUT;
+       gpio_struct.pull = HELIOS_PULL_UP;
+       gpio_struct.value = HELIOS_LVL_HIGH;
+
+       
+       ret = Helios_GPIO_Init((Helios_GPIONum) self->irq, &gpio_struct);
+       FT6X36_LOG("ft6x36 irq=%d, irq ret: %d\n", self->irq, ret);
+
+       
+       gpio_struct.dir = HELIOS_GPIO_OUTPUT;
+       ret = Helios_GPIO_Init((Helios_GPIONum) self->reset, &gpio_struct);
+       FT6X36_LOG("ft6x36 rst=%d, rst ret: %d\n",self->reset, ret);
+
+       
+
+       //RESET
+       Helios_msleep(50);
+       Helios_GPIO_SetLevel((Helios_GPIONum) self->reset, HELIOS_LVL_LOW);
+       Helios_msleep(50);
+       Helios_GPIO_SetLevel((Helios_GPIONum) self->reset, HELIOS_LVL_HIGH);
+       Helios_msleep(200);
+
+
+
+
+#if defined(PLAT_aic8800m40)
+    ret = Helios_I2C_Init((Helios_I2CEnum)self->i2c_no, (Helios_I2CMode)self->i2c_mode,self->group);
+
+#else
+    ret = Helios_I2C_Init((Helios_I2CEnum)self->i2c_no, (Helios_I2CMode)self->i2c_mode);
+#endif
+    if(ret != 0)
+    {
+        mp_raise_ValueError(MP_ERROR_TEXT("i2c init fail"));
+    }
+
+       uint8_t panel_id = 0;
+       FT6X36_RD_Reg(FT6X36_REG_PANEL_ID,&panel_id,1);
+       FT6X36_LOG("panel_id:%x\r\n",panel_id);
+       if(panel_id != FT6X36_VENDID) {
+               //mp_raise_ValueError("panel id read fail");
+       }
+
+
+       uint8_t chip_id = 0;
+       FT6X36_RD_Reg(FT6X36_REG_CHIPID,&chip_id,1);
+       FT6X36_LOG("chip_id:%x\r\n",chip_id);
+       if (chip_id != FT6206_CHIPID && chip_id != FT6236_CHIPID && chip_id != FT6336_CHIPID) {
+               mp_raise_ValueError("chip id read fail");
+       }
+
+       uint8_t send_data = 0;
+       FT6X36_WR_Reg(FT6X36_REG_DEVICE_MODE, &send_data, 1);
+       send_data = FT6X36_DEFAULT_THRESHOLD;
+       FT6X36_WR_Reg(FT6X36_REG_THRESHHOLD, &send_data, 1);
+       send_data = 0x0E; 
+       FT6X36_WR_Reg(FT6X36_REG_TOUCHRATE_ACTIVE, &send_data, 1);
+       
+       
+       if(gt_mutex == 0) {
+               gt_mutex = Helios_Mutex_Create();
+       }
+
+       ft6x36Init = TRUE;
+    return mp_const_none;
+}
+
+STATIC mp_obj_t mp_FT6X36_deinit(mp_obj_t self_in)
+{
+    ft6x36_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       Helios_GPIO_Deinit((Helios_GPIONum)self->irq);
+       Helios_GPIO_Deinit((Helios_GPIONum)self->reset);
+       Helios_I2C_Deinit((Helios_I2CEnum) self->i2c_no);
+    return mp_const_none;
+}
+
+#ifdef TP_STATE_DETECTION
+typedef enum
+{
+       TP_RIGHT_SLIDE,
+       TP_LEFT_SLIDE,
+       TP_UP_SLIDE,
+       TP_DOWN_SLIDE,
+       TP_RETURN,
+       TP_CLICK,
+       TP_ERROR
+}TP_STATE_E;
+
+#define TP_STATE_PUSH(x) {ret = x; goto loop;}
+static TP_STATE_E tp_get_silde_state(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
+{
+       TP_STATE_E ret = TP_ERROR;
+
+       if(x2>x1 && (y2-y1)*(y2-y1) < (x2-x1)*(x2-x1))  //右划
+       {
+               if(x1 < 50) {
+                       // FT6X36_LOG("right return -->\n");
+                       TP_STATE_PUSH(TP_RETURN);
+               }
+               // FT6X36_LOG("right slide -->\n");
+               TP_STATE_PUSH(TP_RIGHT_SLIDE);
+       }
+       if(x2<x1 && (y2-y1)*(y2-y1) < (x2-x1)*(x2-x1))  //左划
+       {
+               // if(x1 > g_ft6x36->width -50) {
+               //      // FT6X36_LOG("left return <--\n");
+               //      TP_STATE_PUSH(TP_RETURN);
+               // }
+               // FT6X36_LOG("left slide <--\n");
+               TP_STATE_PUSH(TP_LEFT_SLIDE);
+       }       
+       if(y2<y1 && (y2-y1)*(y2-y1) > (x2-x1)*(x2-x1))  //上划
+       {
+               // FT6X36_LOG("up slide ^\n");
+               TP_STATE_PUSH(TP_UP_SLIDE);
+       }       
+       if(y2>y1 && (y2-y1)*(y2-y1) > (x2-x1)*(x2-x1))  //下划
+       {
+               // FT6X36_LOG("down slide v\n");
+               TP_STATE_PUSH(TP_DOWN_SLIDE);
+       }
+       if(x1 == x2 && y1 == y2)        //点击
+       {
+               // FT6X36_LOG("click !\n");
+               TP_STATE_PUSH(TP_CLICK);
+       }
+       // FT6X36_LOG("no know !\n");
+loop:
+       TP_CALLBACK_OP(ret);
+
+       return ret;
+}
+
+static void get_silde_state(bool valid, uint16_t x, uint16_t y) {
+       static bool state = false;
+       static uint16_t x_s = 0, y_s = 0;
+       if(state == false && valid == true) {
+               state = true;
+               x_s = x;
+               y_s = y;
+       } else if (state == true && valid == false) {
+               state = false;
+               tp_get_silde_state(x_s, y_s, x, y);
+       }
+}
+
+STATIC mp_obj_t mp_FT6X36_register_usr_cb(mp_obj_t self_in, mp_obj_t callback)
+{
+       ft6x36_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    if (!self) nlr_raise(
+            mp_obj_new_exception_msg(
+                &mp_type_RuntimeError, MP_ERROR_TEXT("GT9xx instance needs to be created before callback is called!")));
+
+    mp_sched_schedule_callback_register(&self->cb, callback);
+
+       return mp_obj_new_int(0);
+}
+#endif
+
+
+uint8_t _touches = 0;
+uint16_t _touchX[2], _touchY[2], _touchEvent[2];
+
+enum TRawEvent
+{
+       PressDown,
+       LiftUp,
+       Contact,
+       NoEvent
+};
+
+
+
+static void _readData(void)
+{
+       const uint8_t size = 16;
+       int16_t i = 0;
+       uint8_t data[16] = {0};
+       FT6X36_RD_Reg(0x00, data, size);
+       _touches = data[FT6X36_REG_NUM_TOUCHES];
+
+       const uint8_t addrShift = 6;
+       
+       for (i = 0; i < 2; i++)
+       {
+               _touchX[i] = data[FT6X36_REG_P1_XH + i * addrShift] & 0x0F;
+               _touchX[i] <<= 8;
+               _touchX[i] |= data[FT6X36_REG_P1_XL + i * addrShift];
+               _touchY[i] = data[FT6X36_REG_P1_YH + i * addrShift] & 0x0F;
+               _touchY[i] <<= 8;
+               _touchY[i] |= data[FT6X36_REG_P1_YL + i * addrShift];
+               _touchEvent[i] = data[FT6X36_REG_P1_XH + i * addrShift] >> 6;
+       }
+}
+
+uint8_t FT6X36_Scan(void)
+{
+       uint8_t buf[4] = {0};
+       uint8_t i=0;
+       uint8_t res=0;
+    uint8_t sta = 0;
+       uint8_t temp = 0;
+
+       if(0 != gt_mutex) {
+               Helios_Mutex_Lock(gt_mutex, HELIOS_WAIT_FOREVER);
+       }
+
+       _readData();
+       if(_touchEvent[0] == 0 || _touchEvent[0] == 2)
+       {
+//             _readData(); //读取触摸点的状态 
+               TPR_Structure.TouchSta = TP_PRES_DOWN;
+               for (i = 0; i < 2; i++) {
+                       TPR_Structure.x[i] = _touchX[i];
+                       TPR_Structure.y[i] = _touchY[i] + (uint16_t)ft6336_y_offset;
+                       
+               }
+               res = 1;
+       } else {
+               if (TPR_Structure.TouchSta & TP_PRES_DOWN) //之前是被按下的
+                       TPR_Structure.TouchSta &= ~0x80;           //触摸松开标记
+               else
+               {
+                       TPR_Structure.x[0] = 0;
+                       TPR_Structure.y[0] = 0;
+               }
+       }
+       
+
+       if(0 != gt_mutex) {
+               Helios_Mutex_Unlock(gt_mutex);
+       }
+       return res;
+}
+
+
+#ifdef CONFIG_LVGL
+static bool FT6X36_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
+{
+       static int16_t last_x = 0;
+    static int16_t last_y = 0;
+    bool valid = false;
+    uint16_t x = last_x;
+    uint16_t y = last_y;
+       
+    ft6x36_obj_t *self = MP_OBJ_TO_PTR(g_ft6x36);
+    if (!self) nlr_raise(
+            mp_obj_new_exception_msg(
+                &mp_type_RuntimeError, MP_ERROR_TEXT("ft6x36 instance needs to be created before callback is called!")));
+
+       
+       self->avg_last = 0;
+
+       if(1 == FT6X36_Scan()) {
+               if (self->x_reverse != 0)
+               {
+                       last_x = self->width - TPR_Structure.x[0];
+               }
+               else
+               {
+                       last_x = TPR_Structure.x[0];
+               }
+               if (self->y_reverse != 0)
+               {
+                       last_y = self->height - TPR_Structure.y[0];
+               }
+               else
+               {
+                       last_y = TPR_Structure.y[0];
+               }
+               valid = true; 
+#ifdef TP_STATE_DETECTION
+               get_silde_state(true,last_x,last_y);
+#endif
+               // FT6X36_LOG("lvgl read x:%d y:%d\n", last_x, last_y);
+       } 
+       else {
+#ifdef TP_STATE_DETECTION
+               get_silde_state(false,last_x,last_y);
+#endif
+       }
+       if (self->x_reverse != 0)
+       {
+               data->point.x = self->width - TPR_Structure.x[0];
+       }
+       else
+       {
+               data->point.x = TPR_Structure.x[0];
+       }
+       if (self->y_reverse != 0)
+       {
+               data->point.y = self->height - TPR_Structure.y[0];
+       }
+       else
+       {
+               data->point.y = TPR_Structure.y[0];
+       }
+    data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
+    return valid;
+
+}
+
+#endif
+
+STATIC mp_obj_t mp_FT6X36_read_xy(mp_obj_t self_in)
+{
+    ft6x36_obj_t *self = MP_OBJ_TO_PTR(g_ft6x36);
+       uint16_t x = 0,y = 0;
+       // FT6X36_LOG("mp_FT6X36_read_xy\n");
+    if (!self) nlr_raise(
+            mp_obj_new_exception_msg(
+                &mp_type_RuntimeError, MP_ERROR_TEXT("FT6X36 instance needs to be created before callback is called!")));
+
+       // FT6X36_LOG("mp_FT6X36_read_xy irq = %d\n", Helios_GPIO_GetLevel(self->irq));
+    if(1 == FT6X36_Scan())
+    {
+               if (self->x_reverse != 0)
+               {
+                       x = self->width - TPR_Structure.x[0];
+               }
+               else
+               {
+                       x = TPR_Structure.x[0];
+               }
+               if (self->y_reverse != 0)
+               {
+                       y = self->height - TPR_Structure.y[0];
+               }
+               else
+               {
+                       y = TPR_Structure.y[0];
+               }
+        mp_obj_t coordinate_list[2] = {mp_obj_new_int(x), mp_obj_new_int(y), };
+        return mp_obj_new_list(2, coordinate_list);
+    }
+       else {
+               FT6X36_LOG("mp_FT6X36_read_xy error\n");
+       }
+    return mp_const_none;
+}
+
+STATIC mp_obj_t mp_FT6X36_suspend(mp_obj_t self_in)
+{
+       ft6x36_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       if (!self) nlr_raise(
+            mp_obj_new_exception_msg(
+                &mp_type_RuntimeError, MP_ERROR_TEXT("FT6X36 instance needs to be created!")));
+
+       if (!ft6x36_is_sleep)
+       {
+               uint8_t suspend_cmd = 3;
+               int ret = 0;//FT6X36_WR_Reg(FT_REG_SUSPEND, &suspend_cmd, 1);
+               if (!ret) ft6x36_is_sleep = TRUE;
+               return mp_obj_new_int(ret);
+       }
+       else
+       {
+               return mp_obj_new_int(-2);      //已是休眠模式则返回-2
+       }
+}
+STATIC mp_obj_t mp_FT6X36_resume(mp_obj_t self_in)
+{
+       ft6x36_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       if (!self) nlr_raise(
+                       mp_obj_new_exception_msg(
+                               &mp_type_RuntimeError, MP_ERROR_TEXT("FT6X36 instance needs to be created!")));
+
+       if (ft6x36_is_sleep)
+       {
+               //RESET
+               Helios_GPIO_SetLevel((Helios_GPIONum) self->reset, HELIOS_LVL_LOW);
+               Helios_msleep(20);
+               Helios_GPIO_SetLevel((Helios_GPIONum) self->reset, HELIOS_LVL_HIGH);
+               Helios_msleep(50);
+               ft6x36_is_sleep = FALSE;
+               return mp_obj_new_int(0);
+       }
+       else
+       {
+               return mp_obj_new_int(-2);      //不是休眠模式则返回-2
+       }
+}
+
+
+STATIC mp_obj_t mp_FT6X36_set_y_offset(mp_obj_t self_in, mp_obj_t in_y_offset)
+{
+       ft6x36_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       if (!self) nlr_raise(
+                       mp_obj_new_exception_msg(
+                               &mp_type_RuntimeError, MP_ERROR_TEXT("FT6X36 instance needs to be created!")));
+       if (!mp_obj_is_int(in_y_offset)){
+        return mp_obj_new_int(-1);
+    }
+       ft6336_y_offset = (int)mp_obj_get_int(in_y_offset);
+       return mp_obj_new_int(0);
+}
+
+#endif /* MICROPY_QPY_TP_FT6X36 */
diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/tp_st1615.c b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/source/tp_st1615.c
new file mode 100644 (file)
index 0000000..78f1054
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**************************************************************************
+ @file tp_st1615.c
+ @brief        touchpad st1615 module interface package.
+
+ DESCRIPTION
+ This module provide the touchpad st1615 interface of micropython.
+
+ INITIALIZATION AND SEQUENCING REQUIREMENTS
+
+
+ ===========================================================================
+ Copyright (c) 2018 Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ Quectel Wireless Solution Proprietary and Confidential.
+ ===========================================================================
+
+                                               EDIT HISTORY FOR FILE
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+WHEN           WHO                     WHAT,WHERE,WHY
+----------  ---------   ---------------------------------------------------
+12/20/2023  felix.ye   Create.
+**************************************************************************/
+
+//////////////////////////////////////////////////////////////////////////////
+// Includes
+//////////////////////////////////////////////////////////////////////////////
+#include <stdio.h>
+#include "runtime.h"
+#include <stdlib.h>
+#include <math.h>
+#include "mphalport.h"
+#include "compile.h"
+#include "repl.h"
+#include "mperrno.h"
+#include "binary.h"
+
+#include <string.h>
+
+#if MICROPY_QPY_TP_ST1615
+
+
+#include "helios_gpio.h"
+#include "helios_iic.h"
+#include "helios_lcd.h"
+#include "helios_fs.h"
+#include "helios_pin.h"
+
+#ifdef CONFIG_LVGL
+#include "lvgl.h"
+#define TP_STATE_DETECTION
+#endif
+
+#ifdef TP_STATE_DETECTION
+#include "callbackdeal.h"
+#endif
+
+#include "helios_debug.h"
+#define ST1615_LOG(msg, ...)      custom_log("ST1615", msg, ##__VA_ARGS__)
+
+// Defines
+//////////////////////////////////////////////////////////////////////////////
+
+// ST1615 寄存器定义
+#define ST1615_ADDR                                                    0x55
+
+#define ST1615_REG_FIRMWARE_VERSION                    0x00
+#define ST1615_REG_STATUS                                      0x01
+#define ST1615_REG_DEVICE_CONTROL                      0x02
+#define ST1615_REG_TIMEOUT_TO_IDLE                     0x03
+#define ST1615_REG_XY_RESOLUTION_H                     0x04 //bit 0~2: Y ; bit 4~6: X ; bit 3,7 : Reserved
+#define ST1615_REG_X_RESOLUTION_L                      0x05
+#define ST1615_REG_Y_RESOLUTION_L                      0x06
+#define ST1615_REG_SENSING_COUNTER_H           0x07
+#define ST1615_REG_SENSING_COUNTER_L           0x08
+#define ST1615_REG_FIRMWARE_REVISION_3         0x0C
+#define ST1615_REG_FIRMWARE_REVISION_2         0x0D
+#define ST1615_REG_FIRMWARE_REVISION_1         0x0E
+#define ST1615_REG_FIRMWARE_REVISION_0         0x0F
+#define ST1615_REG_ADVANCED_TOUCH_INFO         0x10
+#define ST1615_REG_KEY                                         0x11
+#define ST1615_REG_XY0_COORD_H                         0x12
+#define ST1615_REG_X0_COORD_L                          0x13
+#define ST1615_REG_Y0_COORD_L                          0x14
+#define ST1615_REG_XY1_COORD_H                         0x16
+#define ST1615_REG_X1_COORD_H                          0x17
+#define ST1615_REG_Y1_COORD_L                          0x18
+#define ST1615_REG_XY2_COORD_H                         0x1A
+#define ST1615_REG_X2_COORD_H                          0x1B
+#define ST1615_REG_Y2_COORD_L                          0x1C
+#define ST1615_REG_XY3_COORD_H                         0x1E
+#define ST1615_REG_X3_COORD_H                          0x1F
+#define ST1615_REG_Y3_COORD_L                          0x20
+#define ST1615_REG_XY4_COORD_H                         0x22
+#define ST1615_REG_X4_COORD_H                          0x23
+#define ST1615_REG_Y4_COORD_L                          0x24
+#define ST1615_REG_XY5_COORD_H                         0x26
+#define ST1615_REG_X5_COORD_H                          0x27
+#define ST1615_REG_Y5_COORD_L                          0x28
+#define ST1615_REG_XY6_COORD_H                         0x2A
+#define ST1615_REG_X6_COORD_H                          0x2B
+#define ST1615_REG_Y6_COORD_L                          0x2C
+#define ST1615_REG_XY7_COORD_H                         0x2E
+#define ST1615_REG_X7_COORD_H                          0x2F
+#define ST1615_REG_Y7_COORD_L                          0x30
+#define ST1615_REG_XY8_COORD_H                         0x32
+#define ST1615_REG_X8_COORD_H                          0x33
+#define ST1615_REG_Y8_COORD_L                          0x34
+#define ST1615_REG_XY9_COORD_H                         0x36
+#define ST1615_REG_X9_COORD_H                          0x37
+#define ST1615_REG_Y9_COORD_L                          0x38
+#define ST1615_REG_MAX_NUM_SUPPORT                     0x3F
+#define ST1615_REG_PWM0_DUTY                           0xCB
+#define ST1615_REG_PWM1_DUTY                           0xCC
+#define ST1615_REG_PWM2_DUTY                           0xCD
+#define ST1615_REG_PWM3_DUTY                           0xCE
+#define ST1615_REG_PWM_CONTROL                         0xCF
+#define ST1615_REG_MIS_INFO                                    0xF0
+#define ST1615_REG_MIS_CONRTOL                         0xF1
+#define ST1615_REG_SMART_WAKEUP_ID                     0xF2
+#define ST1615_REG_PAGE                                                0xFF
+
+
+
+#define ST1615_DEFAULT_THRESHOLD               22
+
+#define TP_PRES_DOWN 0x80              //触屏被按下
+
+
+#define ST1615_AVG 2
+#define PTR_OBJ(ptr_global) ptr_global ## _obj
+#define TRUE 1
+#define FALSE 0
+
+#define GT_INT Helios_GPIO_GetLevel(g_st1615->irq)
+
+typedef struct mp_ptr_t
+{
+    mp_obj_base_t base;
+    void *ptr;
+} mp_ptr_t;
+
+#define DEFINE_PTR_OBJ_TYPE(ptr_obj_type, ptr_type_qstr)\
+STATIC const mp_obj_type_t ptr_obj_type = {\
+    { &mp_type_type },\
+    .name = ptr_type_qstr,\
+    .buffer_p = { .get_buffer = mp_ptr_get_buffer }\
+}
+
+
+#define DEFINE_PTR_OBJ(ptr_global)\
+DEFINE_PTR_OBJ_TYPE(ptr_global ## _type, MP_QSTR_ ## ptr_global);\
+STATIC const mp_ptr_t PTR_OBJ(ptr_global) = {\
+    { &ptr_global ## _type },\
+    &ptr_global\
+}
+
+STATIC mp_int_t mp_ptr_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags)
+{
+    mp_ptr_t *self = MP_OBJ_TO_PTR(self_in);
+
+    if (flags & MP_BUFFER_WRITE) {
+        // read-only ptr
+        //return 1;
+    }
+
+    bufinfo->buf = &self->ptr;
+    bufinfo->len = sizeof(self->ptr);
+    bufinfo->typecode = BYTEARRAY_TYPECODE;
+    return 0;
+}
+
+typedef struct _st1615_obj_t
+{
+    mp_obj_base_t base;
+
+    uint8_t i2c_no;
+       uint8_t i2c_mode;
+    uint8_t irq;
+       uint8_t reset;
+       uint8_t x_reverse;
+       uint8_t y_reverse;
+       uint32_t sleep_us;
+
+    int16_t x_min;
+    int16_t y_min;
+    int16_t x_max;
+    int16_t y_max;
+    bool x_inv;
+    bool y_inv;    
+    bool xy_swap;
+       
+
+    int16_t avg_buf_x[ST1615_AVG];
+    int16_t avg_buf_y[ST1615_AVG];
+    uint8_t avg_last;
+       int16_t width;
+       int16_t height;
+       int16_t addr;
+
+#ifdef TP_STATE_DETECTION
+       c_callback_t cb;
+#endif
+
+} st1615_obj_t;
+
+STATIC st1615_obj_t *g_st1615 = NULL;
+
+static Helios_Mutex_t gt_mutex;
+
+static uint8_t st1615Init = FALSE;
+static uint8_t st1615_is_sleep = FALSE;
+static int st1615_y_offset = 0;
+
+typedef struct
+{
+       uint8_t TouchSta;
+       uint16_t x[2];
+       uint16_t y[2];
+
+} TouchPointRefTypeDef1;
+static TouchPointRefTypeDef1 TPR_Structure;
+
+#ifdef TP_STATE_DETECTION
+#define TP_CALLBACK_OP(tp_state)     do{                                                                                                                                                                  \
+                                                                                       if(g_st1615->cb.cb != NULL) {                                                  \
+                                               st_CallBack_TP *tp_cb = malloc(sizeof(st_CallBack_TP));                    \
+                                               if(NULL != tp_cb) {                                                        \
+                                                       tp_cb->callback = g_st1615->cb;                                        \
+                                                       tp_cb->state = tp_state;                                               \
+                                                       qpy_send_msg_to_callback_deal_thread(CALLBACK_TYPE_ID_TP, tp_cb);      \
+                                                       }                                                                                                                                                  \
+                                                                                       }                                                                              \
+                                        }while(0)
+#endif
+
+
+int ST1615_RD_Reg(uint8_t reg,uint8_t *buf,uint8_t len)
+{
+    uint8_t reg_addr = reg;
+       return HELIOS_I2C_Read((Helios_I2CEnum)g_st1615->i2c_no, g_st1615->addr, &reg_addr, 1, (void*)buf, len, 0);
+} 
+
+int ST1615_WR_Reg(uint8_t reg,uint8_t *buf,uint8_t len)
+{
+    uint8_t reg_addr = reg;
+       return HELIOS_I2C_Write((Helios_I2CEnum)g_st1615->i2c_no, g_st1615->addr, &reg_addr, 1, buf, len);
+}
+
+int ST1615_WR_no_Reg(uint8_t *buf,uint8_t len)
+{
+    uint8_t reg_addr = 0;
+       return HELIOS_I2C_Write((Helios_I2CEnum)g_st1615->i2c_no, g_st1615->addr, &reg_addr, 0, buf, len);
+}
+
+STATIC mp_obj_t mp_activate_ST1615(mp_obj_t self_in)
+{
+    st1615_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    g_st1615 = self;
+    return mp_const_none;
+}
+
+STATIC mp_obj_t ST1615_make_new(const mp_obj_type_t *type,
+                               size_t n_args,
+                               size_t n_kw,
+                               const mp_obj_t *all_args)
+{
+    enum{
+        ARG_i2c_no,
+        ARG_i2c_mode,
+        ARG_irq,
+               ARG_x_reverse,
+               ARG_y_reverse,
+        ARG_reset,
+
+        ARG_x_inv,
+        ARG_y_inv,
+        ARG_xy_swap,
+               
+
+               ARG_width,
+               ARG_height,
+
+               ARG_addr,
+    };
+
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_i2c_no, MP_ARG_INT, {.u_int = 0}},
+        { MP_QSTR_i2c_mode, MP_ARG_INT, {.u_int = 0}},
+        { MP_QSTR_irq, MP_ARG_INT, {.u_int = 2}},
+               { MP_QSTR_x_reverse, MP_ARG_INT, {.u_int = 0}},
+               { MP_QSTR_y_reverse, MP_ARG_INT, {.u_int = 0}},
+        { MP_QSTR_reset, MP_ARG_INT, {.u_int = 4}},
+
+        { MP_QSTR_x_inv, MP_ARG_BOOL, {.u_obj = mp_const_true}},
+        { MP_QSTR_y_inv, MP_ARG_BOOL, {.u_obj = mp_const_true}},
+        { MP_QSTR_xy_swap, MP_ARG_BOOL, {.u_obj = mp_const_false}},
+        { MP_QSTR_width, MP_ARG_INT, {.u_int = 240}},
+        { MP_QSTR_height, MP_ARG_INT, {.u_int = 240}},
+               { MP_QSTR_addr, MP_ARG_INT, {.u_int = ST1615_ADDR}},
+
+    };
+
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+    st1615_obj_t *self = m_new_obj(st1615_obj_t);
+    self->base.type = type;
+
+    self->i2c_no = args[ARG_i2c_no].u_int;
+       self->i2c_mode = args[ARG_i2c_mode].u_int;
+    self->irq = args[ARG_irq].u_int;
+       self->x_reverse = args[ARG_x_reverse].u_int;
+       self->y_reverse = args[ARG_y_reverse].u_int;
+       self->reset = args[ARG_reset].u_int;
+       self->width = args[ARG_width].u_int;
+       self->height = args[ARG_height].u_int;
+       self->addr = args[ARG_addr].u_int;
+
+       #ifdef TP_STATE_DETECTION
+       memset(&(self->cb), 0, sizeof(c_callback_t));
+       #endif
+    return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t mp_ST1615_init(mp_obj_t self_in);
+STATIC mp_obj_t mp_ST1615_deinit(mp_obj_t self_in);
+#ifdef CONFIG_LVGL
+STATIC bool ST1615_read(lv_indev_drv_t * indev_drv, lv_indev_data_t *data);
+#endif
+STATIC mp_obj_t mp_ST1615_read_xy(mp_obj_t self_in);
+#ifdef TP_STATE_DETECTION
+STATIC mp_obj_t mp_ST1615_register_usr_cb(mp_obj_t self_in, mp_obj_t callback);
+#endif
+STATIC mp_obj_t mp_ST1615_suspend(mp_obj_t self_in);
+STATIC mp_obj_t mp_ST1615_resume(mp_obj_t self_in);
+STATIC mp_obj_t mp_ST1615_set_y_offset(mp_obj_t self_in, mp_obj_t in_y_offset);
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_init_ST1615_obj, mp_ST1615_init);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_deinit_ST1615_obj, mp_ST1615_deinit);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_activate_ST1615_obj, mp_activate_ST1615);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_readxy_ST1615_obj, mp_ST1615_read_xy);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_suspend_ST1615_obj, mp_ST1615_suspend);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_resume_ST1615_obj, mp_ST1615_resume);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_set_y_offset_ST1615_obj, mp_ST1615_set_y_offset);
+
+#ifdef CONFIG_LVGL
+DEFINE_PTR_OBJ(ST1615_read);
+#endif
+
+#ifdef TP_STATE_DETECTION
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_ST1615_register_usr_cb_obj, mp_ST1615_register_usr_cb);
+#endif
+
+STATIC const mp_rom_map_elem_t ST1615_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mp_init_ST1615_obj) },
+    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mp_deinit_ST1615_obj) },
+    { MP_ROM_QSTR(MP_QSTR_activate), MP_ROM_PTR(&mp_activate_ST1615_obj) },
+       { MP_ROM_QSTR(MP_QSTR_read_xy), MP_ROM_PTR(&mp_readxy_ST1615_obj) },
+       { MP_ROM_QSTR(MP_QSTR_suspend), MP_ROM_PTR(&mp_suspend_ST1615_obj) },
+       { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mp_resume_ST1615_obj) },
+       { MP_ROM_QSTR(MP_QSTR_set_y_offset), MP_ROM_PTR(&mp_set_y_offset_ST1615_obj) },
+#ifdef CONFIG_LVGL
+    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&PTR_OBJ(ST1615_read)) },
+#endif
+#ifdef TP_STATE_DETECTION
+       { MP_ROM_QSTR(MP_QSTR_set_callback), MP_ROM_PTR(&mp_ST1615_register_usr_cb_obj) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(ST1615_locals_dict, ST1615_locals_dict_table);
+
+const mp_obj_type_t tp_ST1615_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_ST1615,
+    .make_new = ST1615_make_new,
+    .locals_dict = (mp_obj_dict_t*)&ST1615_locals_dict,
+};
+
+mp_obj_t mp_ST1615_init(mp_obj_t self_in)
+{
+
+       int ret;
+    uint8_t temp;
+
+    st1615_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_activate_ST1615(self_in);
+
+       
+       Helios_GPIOInitStruct gpio_struct = {0};
+       gpio_struct.dir = HELIOS_GPIO_INPUT;
+       gpio_struct.pull = HELIOS_PULL_UP;
+       gpio_struct.value = HELIOS_LVL_HIGH;
+
+       ret = Helios_GPIO_Init((Helios_GPIONum) self->irq, &gpio_struct);
+       ST1615_LOG("st1615 irq=%d, irq ret: %d\n", self->irq, ret);
+
+       gpio_struct.dir = HELIOS_GPIO_OUTPUT;
+       gpio_struct.pull = HELIOS_PULL_UP;
+       gpio_struct.value = HELIOS_LVL_LOW;
+       ret = Helios_GPIO_Init((Helios_GPIONum) self->reset, &gpio_struct);
+       ST1615_LOG("st1615 rst=%d, rst ret: %d\n",self->reset, ret);
+
+       //RESET
+       Helios_msleep(20);
+       Helios_GPIO_SetLevel((Helios_GPIONum) self->reset, HELIOS_LVL_HIGH);
+       Helios_msleep(20);
+       Helios_GPIO_SetLevel((Helios_GPIONum) self->reset, HELIOS_LVL_LOW);
+       Helios_msleep(20);
+       Helios_GPIO_SetLevel((Helios_GPIONum) self->reset, HELIOS_LVL_HIGH);
+       Helios_msleep(150);
+
+
+#if defined(PLAT_aic8800m40)
+    ret = Helios_I2C_Init((Helios_I2CEnum)self->i2c_no, (Helios_I2CMode)self->i2c_mode,self->group);
+
+#else
+    ret = Helios_I2C_Init((Helios_I2CEnum)self->i2c_no, (Helios_I2CMode)self->i2c_mode);
+#endif
+    if(ret != 0)
+    {
+        mp_raise_ValueError(MP_ERROR_TEXT("i2c init fail"));
+    }
+
+       uint8_t firmware_version = 0;
+       uint8_t max_num = 0;
+
+       ST1615_RD_Reg(ST1615_REG_FIRMWARE_VERSION,&firmware_version,1);
+       ST1615_LOG("firmware_version: %x\r\n", firmware_version);
+
+       ST1615_RD_Reg(ST1615_REG_MAX_NUM_SUPPORT,&max_num,1);
+       ST1615_LOG("firmware_version: %x\r\n", max_num);
+       
+       if(gt_mutex == 0) {
+               gt_mutex = Helios_Mutex_Create();
+       }
+
+       st1615Init = TRUE;
+    return mp_const_none;
+}
+
+STATIC mp_obj_t mp_ST1615_deinit(mp_obj_t self_in)
+{
+    st1615_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       Helios_GPIO_Deinit((Helios_GPIONum)self->irq);
+       Helios_GPIO_Deinit((Helios_GPIONum)self->reset);
+       Helios_I2C_Deinit((Helios_I2CEnum) self->i2c_no);
+    return mp_const_none;
+}
+
+#ifdef TP_STATE_DETECTION
+typedef enum
+{
+       TP_RIGHT_SLIDE,
+       TP_LEFT_SLIDE,
+       TP_UP_SLIDE,
+       TP_DOWN_SLIDE,
+       TP_RETURN,
+       TP_CLICK,
+       TP_ERROR,
+       TP_PRESS,
+       TP_LIFT,
+       TP_LONG_PRESS
+}TP_STATE_E;
+
+#define TP_STATE_PUSH(x) {ret = x; goto loop;}
+static TP_STATE_E tp_get_silde_state(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, int tick_f)
+{
+       TP_STATE_E ret = TP_ERROR;
+       // if(tick_f > 10)
+       // {
+       //      //ST1615_LOG("tp is pressd in long time\n");
+       //      TP_STATE_PUSH(TP_LONG_PRESS);
+       //      //TP_STATE_PUSH(TP_LIFT);
+       // } 
+       // else
+       // {
+               if(x2>x1 && (y2-y1)*(y2-y1) < (x2-x1)*(x2-x1))  //右划,东芯泰合客户不需要返回手势,故注释掉,目前只有东芯泰合客户用这个tp型号。
+               {
+                       // if(x1 < 50) {
+                       //      // ST1615_LOG("right return -->\n");
+                               
+                       //      TP_STATE_PUSH(TP_RETURN);
+                       //      //TP_STATE_PUSH(TP_LIFT);
+                       // }
+                       // ST1615_LOG("right slide -->\n");
+                       
+                       if((x2-x1) < 20)
+                       {
+                               if(tick_f > 10)
+                               {
+                                       TP_STATE_PUSH(TP_LONG_PRESS);
+                               }
+                               TP_STATE_PUSH(TP_CLICK);
+                       }
+                       else
+                       {
+                               TP_STATE_PUSH(TP_RIGHT_SLIDE);
+                       }
+                       
+                       //TP_STATE_PUSH(TP_LIFT);
+               }
+               if(x2<x1 && (y2-y1)*(y2-y1) < (x2-x1)*(x2-x1))  //左划
+               {
+                       // TEST_LOG("x1 = 0x%d\n,x2 = 0x%d\n,y1 = 0x%d\n,y2 = 0x%d\n",x1,x2,y1,y2);
+                       if((x1-x2) < 20)
+                       {
+                               if(tick_f > 10)
+                               {
+                                       TP_STATE_PUSH(TP_LONG_PRESS);
+                               }
+                               TP_STATE_PUSH(TP_CLICK); // Add by Arno.Ding : 防止客户点击事件手指有短距离的偏移从而判断成了滑动事件
+                       }
+                       else
+                       {
+                               TP_STATE_PUSH(TP_LEFT_SLIDE);
+                       }
+                       //TP_STATE_PUSH(TP_LIFT);
+               }       
+               if(y2<y1 && (y2-y1)*(y2-y1) > (x2-x1)*(x2-x1))  //上划
+               {
+                       // ST1615_LOG("up slide ^\n");
+                       // TEST_LOG("x1 = 0x%d\n,x2 = 0x%d\n,y1 = 0x%d\n,y2 = 0x%d\n",x1,x2,y1,y2);
+                       if((y1-y2) < 20)
+                       {
+                               if(tick_f > 10)
+                               {
+                                       TP_STATE_PUSH(TP_LONG_PRESS);
+                               }
+                               TP_STATE_PUSH(TP_CLICK);
+                       }
+                       else 
+                       {
+                               TP_STATE_PUSH(TP_UP_SLIDE);
+                       }
+                       //TP_STATE_PUSH(TP_LIFT);
+               }       
+               if(y2>y1 && (y2-y1)*(y2-y1) > (x2-x1)*(x2-x1))  //下划
+               {
+                       // ST1615_LOG("down slide v\n");
+                       // TEST_LOG("x1 = 0x%d\n,x2 = 0x%d\n,y1 = 0x%d\n,y2 = 0x%d\n",x1,x2,y1,y2);
+                       if((y2-y1) < 20)
+                       {
+                               if(tick_f > 10)
+                               {
+                                       TP_STATE_PUSH(TP_LONG_PRESS);
+                               }
+                               TP_STATE_PUSH(TP_CLICK);
+                       }
+                       else
+                       {
+                               TP_STATE_PUSH(TP_DOWN_SLIDE);
+                       }
+                       
+                       //TP_STATE_PUSH(TP_LIFT);
+               }
+               if(x1 == x2 && y1 == y2)        //点击
+               {
+                       // ST1615_LOG("click !\n");
+                       if(tick_f > 10)
+                       {
+                               TP_STATE_PUSH(TP_LONG_PRESS);
+                       }
+                       else TP_STATE_PUSH(TP_CLICK);
+                       //TP_STATE_PUSH(TP_LIFT);
+               }
+       // }
+loop:
+       TP_CALLBACK_OP(ret);
+       TP_CALLBACK_OP(TP_LIFT);
+
+       return ret;
+}
+
+static void get_silde_state(bool valid, uint16_t x, uint16_t y, int tick_t) {
+       static bool state = false;
+       static uint16_t x_s = 0, y_s = 0;
+       static int tick_temp = 0;
+       tick_temp = tick_t ;
+       //ST1615_LOG("tick_temp = %d\n, tick = %d\n", tick_temp, tick_t);
+       if(state == false && valid == true) {
+               state = true;
+               x_s = x;
+               y_s = y;
+               TP_CALLBACK_OP(TP_PRESS);
+       } else if (state == true && valid == false) {
+               state = false;
+               //ST1615_LOG("tick_temp = %d\n", tick_temp);
+               tp_get_silde_state(x_s, y_s, x, y, tick_temp);
+       }
+}
+
+STATIC mp_obj_t mp_ST1615_register_usr_cb(mp_obj_t self_in, mp_obj_t callback)
+{
+       st1615_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    if (!self) nlr_raise(
+            mp_obj_new_exception_msg(
+                &mp_type_RuntimeError, MP_ERROR_TEXT("GT9xx instance needs to be created before callback is called!")));
+
+    mp_sched_schedule_callback_register(&self->cb, callback);
+
+       return mp_obj_new_int(0);
+}
+#endif
+
+
+uint8_t _touches = 0;
+uint16_t _touchX, _touchY;
+int _touchEvent[] = {0};
+
+enum TRawEvent
+{
+       PressDown,
+       LiftUp,
+       Contact,
+       NoEvent
+};
+
+
+
+static void _readData(void)
+{
+       const uint8_t size = 16;
+       uint8_t data[64] = {0};
+       if (ST1615_RD_Reg(0x12, data, size) < 0) {
+               ST1615_LOG("ST1615_RD_Reg fail !!! \n");
+               return;
+       }
+       ST1615_LOG("ST1615_RD_Reg 0x12:%d, 0x13:%d, 0x14:%d, 0x15:%d \n", data[0], data[1], data[3], data[4]);
+       _touches = data[ST1615_REG_MAX_NUM_SUPPORT];
+
+       _touchX = (int)(data[0] & 0x70) << 4 | data[1];
+       _touchY = (int)(data[0] & 0x0F) << 8 | data[2];
+       _touchEvent[0] = data[0] & 0x80;
+}
+
+uint8_t ST1615_Scan(void)
+{
+       uint8_t buf[4] = {0};
+       uint8_t i=0;
+       uint8_t res=0;
+    uint8_t sta = 0;
+       uint8_t temp = 0;
+
+       if(0 != gt_mutex) {
+               Helios_Mutex_Lock(gt_mutex, HELIOS_WAIT_FOREVER);
+       }
+
+       _readData();
+
+       if(_touchEvent[0])
+       {
+               TPR_Structure.TouchSta = TP_PRES_DOWN;
+               TPR_Structure.x[i] = _touchX;
+               TPR_Structure.y[i] = _touchY + st1615_y_offset;
+               res = 1;
+       } else {
+               if (TPR_Structure.TouchSta & TP_PRES_DOWN) //之前是被按下的
+               {
+                       TPR_Structure.TouchSta &= ~0x80;           //触摸松开标记
+               }
+               else
+               {
+                       TPR_Structure.x[0] = 0;
+                       TPR_Structure.y[0] = 0;
+               }
+       }
+
+       if(0 != gt_mutex) {
+               Helios_Mutex_Unlock(gt_mutex);
+       }
+       return res;
+}
+
+//Revised by Arno.Ding 2024/07/03
+//东芯泰合客户需要在触摸原先的左右上下滑动点击事件的基础上新增长按事件,而且需要给出按下和抬起的事件回调,此处函数为时间间隔为20ms一次轮询读取的方式
+//此处修改为按下后立刻抛出按下事件的回调,并开始记录tick,等tick超过10,判断为长按事件,并且在所有事件回调抛出后,再抛出抬起事件回调
+
+#ifdef CONFIG_LVGL
+static bool ST1615_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
+{
+       static int16_t last_x = 0;
+    static int16_t last_y = 0;
+    bool valid = false;
+    uint16_t x = last_x;
+    uint16_t y = last_y;
+       static int tick = 0;
+       
+    st1615_obj_t *self = MP_OBJ_TO_PTR(g_st1615);
+    if (!self) nlr_raise(
+            mp_obj_new_exception_msg(
+                &mp_type_RuntimeError, MP_ERROR_TEXT("st1615 instance needs to be created before callback is called!")));
+
+       
+       self->avg_last = 0;
+
+       if(1 == ST1615_Scan()) {
+               tick++;
+               if (self->x_reverse != 0)
+               {
+                       last_x = self->width - TPR_Structure.x[0];
+               }
+               else
+               {
+                       last_x = TPR_Structure.x[0];
+               }
+               if (self->y_reverse != 0)
+               {
+                       last_y = self->height - TPR_Structure.y[0];
+               }
+               else
+               {
+                       last_y = TPR_Structure.y[0];
+               }
+               valid = true;
+
+               //ST1615_LOG("tick =  %d\n", tick);
+#ifdef TP_STATE_DETECTION
+               get_silde_state(true, last_x, last_y, tick);
+
+#endif
+       } 
+       else {
+               
+#ifdef TP_STATE_DETECTION
+               //ST1615_LOG("tick671 =  %d\n", tick);
+               get_silde_state(false, last_x, last_y, tick);
+               tick = 0;
+#endif
+       }
+       if (self->x_reverse != 0)
+       {
+               data->point.x = self->width - TPR_Structure.x[0];
+       }
+       else
+       {
+               data->point.x = TPR_Structure.x[0];
+       }
+       if (self->y_reverse != 0)
+       {
+               data->point.y = self->height - TPR_Structure.y[0];
+       }
+       else
+       {
+               data->point.y = TPR_Structure.y[0];
+       }
+    data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
+       //ST1615_LOG("valid =  %d\n", valid);
+    return valid;
+
+}
+
+#endif
+
+STATIC mp_obj_t mp_ST1615_read_xy(mp_obj_t self_in)
+{
+    st1615_obj_t *self = MP_OBJ_TO_PTR(g_st1615);
+       uint16_t x = 0,y = 0;
+
+    if (!self) nlr_raise(
+            mp_obj_new_exception_msg(
+                &mp_type_RuntimeError, MP_ERROR_TEXT("ST1615 instance needs to be created before callback is called!")));
+
+    if(1 == ST1615_Scan())
+    {
+               if (self->x_reverse != 0)
+               {
+                       x = self->width - TPR_Structure.x[0];
+               }
+               else
+               {
+                       x = TPR_Structure.x[0];
+               }
+               if (self->y_reverse != 0)
+               {
+                       y = self->height - TPR_Structure.y[0];
+               }
+               else
+               {
+                       y = TPR_Structure.y[0];
+               }
+        mp_obj_t coordinate_list[2] = {mp_obj_new_int(x), mp_obj_new_int(y)};
+        return mp_obj_new_list(2, coordinate_list);
+    }
+       else {
+               ST1615_LOG("mp_ST1615_read_xy error\n");
+       }
+    return mp_const_none;
+}
+
+STATIC mp_obj_t mp_ST1615_suspend(mp_obj_t self_in)
+{
+       st1615_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       if (!self) nlr_raise(
+            mp_obj_new_exception_msg(
+                &mp_type_RuntimeError, MP_ERROR_TEXT("ST1615 instance needs to be created!")));
+
+       if (!st1615_is_sleep)
+       {
+               //unsigned char SlpKey[] = {0, 'S', 0, 'T', 0, 'X', 0, '_', 0, 'S', 0, 'L', 0, 'P', 0, '1', 0, 0x5A};
+               // for (int i = 0; i < sizeof(SlpKey); i += 2)
+               // {
+               //      if (ST1615_WR_no_Reg(&SlpKey[i], 2) < 0)
+               //      {
+               //              ST1615_LOG("Entering SLP1 Mode fail.");
+               //              return mp_obj_new_int(-2);
+               //      }
+               // }
+               uint8_t suspend_cmd = 2;
+               int ret = ST1615_WR_Reg(ST1615_REG_DEVICE_CONTROL, &suspend_cmd, 1);
+               if (!ret) st1615_is_sleep = TRUE;
+               return mp_obj_new_int(0);
+       }
+       else
+       {
+               return mp_obj_new_int(-2);
+       }
+}
+STATIC mp_obj_t mp_ST1615_resume(mp_obj_t self_in)
+{
+       st1615_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       if (!self) nlr_raise(
+                       mp_obj_new_exception_msg(
+                               &mp_type_RuntimeError, MP_ERROR_TEXT("ST1615 instance needs to be created!")));
+
+       if (st1615_is_sleep)
+       {
+               //RESET
+               Helios_GPIO_SetLevel((Helios_GPIONum) self->reset, HELIOS_LVL_LOW);
+               Helios_msleep(20);
+               Helios_GPIO_SetLevel((Helios_GPIONum) self->reset, HELIOS_LVL_HIGH);
+               Helios_msleep(250);
+               st1615_is_sleep = FALSE;
+               return mp_obj_new_int(0);
+       }
+       else
+       {
+               return mp_obj_new_int(-2);
+       }
+}
+
+
+STATIC mp_obj_t mp_ST1615_set_y_offset(mp_obj_t self_in, mp_obj_t in_y_offset)
+{
+       st1615_obj_t *self = MP_OBJ_TO_PTR(self_in);
+       if (!self) nlr_raise(
+                       mp_obj_new_exception_msg(
+                               &mp_type_RuntimeError, MP_ERROR_TEXT("ST1615 instance needs to be created!")));
+       if (!mp_obj_is_int(in_y_offset)){
+        return mp_obj_new_int(-1);
+    }
+       st1615_y_offset = (int)mp_obj_get_int(in_y_offset);
+       return mp_obj_new_int(0);
+}
+
+#endif /* MICROPY_QPY_TP_ST1615 */