/*============================================================================ Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved. Quectel Wireless Solution Proprietary and Confidential. =============================================================================*/ /*=========================================================================== EDIT HISTORY FOR MODULE This section contains comments describing changes made to the module. Notice that changes are listed in reverse chronological order. WHEN WHO WHAT, WHERE, WHY ---------- ------------ ---------------------------------------------------- =============================================================================*/ #include #include #include #include #include "ql_log.h" #include "ql_api_osi.h" #include "ql_osi_def.h" #include "ql_api_datacall.h" #include "ch395_adapter.h" #include "CH395CMD.H" #include "CH395INC.H" #include "CH395.H" /*======================================================================== * Macro Definition *========================================================================*/ #define CH395_LOG_LEVEL QL_LOG_LEVEL_INFO #define CH395_DEMO_LOG(msg, ...) QL_LOG(CH395_LOG_LEVEL, "ch395_log", msg, ##__VA_ARGS__) #define CH395_ERR_UNKNOW_RETRY_TIME (5 * 1000) #define CH395_ERR_OPEN_RETRY_TIME (2 * 100) #define CH395_CONNECTED_CHECK_STATUS_TIME (20 * 1000) #define CH395_CHECK_STATUS_TIME (10 * 1000) #define CH395_CHECK_STATUS_RESET_CNT (5) #define CH395_ERROR_RETRY_TIMES 5 #define CH395_BUFFER_SIZE 1514 //max mac frame len #define CH395_SOCKET_INDEX 0 #define CH395_SIM_ID_MAX 2 /*======================================================================== * Enumeration Definition *========================================================================*/ /*======================================================================== * Type Definition *=========================================================================*/ typedef struct ch395_list_t { struct ch395_list_t *next; }ch395_list_t; typedef struct { struct ch395_list_t list; uint8_t *data; uint32_t len; }ch395_elem_t; struct _CH395_SYS { uint8_t IPAddr[4]; /* CH395IP地址 32bit*/ uint8_t GWIPAddr[4]; /* CH395网关地址 32bit*/ uint8_t MASKAddr[4]; /* CH395子网掩码 32bit*/ uint8_t MacAddr[6]; /* CH395MAC地址 48bit*/ uint8_t PHYStat; /* CH395 PHY状态码 8bit*/ uint8_t MackFilt; /* CH395 MAC过滤,默认为接收广播,接收本机MAC 8bit*/ uint32_t RetranCount; /* 重试次数 默认为10次*/ uint32_t RetranPeriod; /* 重试周期,单位MS,默认200MS */ uint8_t IntfMode; /* 接口模式 */ uint8_t UnreachIPAddr[4]; /* 不可到达IP */ uint16_t UnreachPort; /* 不可到达端口 */ }; struct _SOCK_INF { uint8_t IPAddr[4]; /* socket目标IP地址 32bit*/ uint8_t MacAddr[6]; /* socket目标地址 48bit*/ uint8_t ProtoType; /* 协议类型 */ uint8_t ScokStatus; /* socket状态,参考scoket状态定义 */ uint8_t TcpMode; /* TCP模式 */ uint32_t IPRAWProtoType; /* IPRAW 协议类型 */ uint16_t DesPort; /* 目的端口 */ uint16_t SourPort; /* 目的端口 */ uint16_t SendLen; /* 发送数据长度 */ uint16_t RemLen; /* 剩余长度 */ uint8_t *pSend; /* 发送指针 */ }; typedef struct { /* API related. See ql_ethernet_ctx_s in ql_api_ethernet.h. */ uint8_t ip4[4]; uint8_t gw[4]; uint8_t netmask[4]; uint8_t mac[6]; uint8_t dns1[4]; uint8_t dns2[4]; ql_ethernet_mode_e mode; bool cover; uint8_t dhcp; uint8_t sim_id; int profile_idx; ql_ethernet_route_prefer_e prefer; /* Task related. */ ql_task_t task; ql_timer_t timer; uint32_t curr_id; ch395_app_net_status_e status; uint8_t status_reset_cnt; ch395_app_reset_cb_t reset_cb; ch395_app_notify_cb_t notify_cb; ql_mutex_t mutex; }ch395_demo_manager_s; /*======================================================================== * Global Variable *========================================================================*/ /* 常用变量定义 */ uint8_t MyBuffer[CH395_BUFFER_SIZE]; /* 数据缓冲区 */ uint8_t SendBuffer[CH395_BUFFER_SIZE]; uint32_t SendBufferLen = 0; struct _SOCK_INF SockInf; /* 保存Socket信息 */ struct _CH395_SYS CH395Inf; /* 保存CH395信息 */ /* CH395相关定义 */ uint8_t CH395IPAddr[4] = {192,168,1,1}; /* CH395IP地址 */ uint8_t CH395GWIPAddr[4] = {192,168,1,1}; /* CH395网关 */ uint8_t CH395IPMask[4] = {255,255,255,0}; /* CH395子网掩码 */ ch395_demo_manager_s ch395_demo_manager = {0}; static ql_mutex_t list_lock = NULL; ch395_list_t list_header; /*======================================================================== * function Definition *========================================================================*/ uint8_t CH395Init(void); uint8_t CH395SocketInitOpen(void); bool ch395_app_deinit(void* argv); void ch395_create_mutex(ql_mutex_t* lockaddr) { if(!lockaddr) { return; } if(NULL == *lockaddr) { ql_rtos_mutex_create(lockaddr); } } void ch395_delete_mutex(ql_mutex_t lock) { if(NULL == lock) { return; } ql_rtos_mutex_delete(lock); } void ch395_try_lock(ql_mutex_t lock) { if(NULL == lock) { return; } ql_rtos_mutex_lock(lock, 0xffffffffUL); } void ch395_unlock(ql_mutex_t lock) { if(NULL == lock) { return; } ql_rtos_mutex_unlock(lock); } void ch395_list_init(ch395_list_t *header) { header->next = NULL; } bool ch395_list_add_tail(ch395_list_t *header,uint8_t *data,uint32_t len) { /* Create new node and add it to tail. */ ch395_elem_t *elem = (ch395_elem_t *)calloc(1,sizeof(ch395_elem_t)); if(!elem) { return false; } elem->list.next = NULL; elem->data = (uint8_t *)calloc(1,len); if(!(elem->data)) { return false; } memcpy(elem->data,data,len); elem->len = len; ch395_list_t *p = header; while(p->next) { p = p->next; } p->next = &elem->list; return true; }; bool ch395_list_is_empty(ch395_list_t *header) { return !(header->next); } bool ch395_list_get_head(ch395_list_t *header,uint8_t *data,uint32_t *len) { /* Get and delete the first node. */ if(ch395_list_is_empty(header)) { return false; } ch395_list_t *p = header; ch395_elem_t *elem = (ch395_elem_t*)(header->next); memcpy(data,elem->data,elem->len); *len = elem->len; p->next = elem->list.next; free(elem->data); free(elem); return true; } void ch395_app_send_event(ql_task_t task,uint32_t id, uint32_t param1, uint32_t param2, uint32_t param3) { ql_event_t msg; msg.id = id; msg.param1 = param1; msg.param2 = param2; msg.param3 = param3; ql_rtos_event_send(task, &msg); } bool ch395_app_check_if_no_err(uint8_t err) { if (err == CMD_ERR_SUCCESS) return true; /* 操作成功 */ CH395_DEMO_LOG("CH395 Error: %02X\n", (uint16_t)err); /* 显示错误 */ ch395_demo_manager_s* manager = &ch395_demo_manager; int ret = 0; switch(err) { //硬件错误 default: case CH395_ERR_UNKNOW: { ret = ql_rtos_timer_start(manager->timer, CH395_ERR_UNKNOW_RETRY_TIME, 0); if (ret != QL_OSI_SUCCESS) { CH395_DEMO_LOG("timer start failed"); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_TRY_RESET,0,0,0); } break; } //CH395内部socket错误 case CH395_ERR_OPEN: { CH395CloseSocket(CH395_SOCKET_INDEX); ret = ql_rtos_timer_start(manager->timer, CH395_ERR_OPEN_RETRY_TIME, 0); if (ret != QL_OSI_SUCCESS) { CH395_DEMO_LOG("timer start failed"); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_TRY_CONNECT,0,0,0); } break; } } return false; } void InitCH395InfParam(void) { ch395_demo_manager_s* manager = &ch395_demo_manager; memset(&CH395Inf,0,sizeof(CH395Inf)); /* 将CH395Inf全部清零*/ memcpy(CH395Inf.IPAddr,manager->ip4,sizeof(CH395IPAddr)); /* 将IP地址写入CH395Inf中 */ memcpy(CH395Inf.GWIPAddr,manager->gw,sizeof(CH395GWIPAddr)); /* 将网关IP地址写入CH395Inf中 */ memcpy(CH395Inf.MASKAddr,manager->netmask,sizeof(CH395IPMask)); /* 将子网掩码写入CH395Inf中 */ CH395CMDGetMACAddr(CH395Inf.MacAddr); CH395_DEMO_LOG("CH395EVT:get mac %02x:%02x:%02x:%02x:%02x:%02x", CH395Inf.MacAddr[0],CH395Inf.MacAddr[1],CH395Inf.MacAddr[2], CH395Inf.MacAddr[3],CH395Inf.MacAddr[4],CH395Inf.MacAddr[5]); memcpy((void*)manager->mac,(void*)CH395Inf.MacAddr,sizeof(manager->mac)); } void InitSocketParam(void) { memset(&SockInf,0,sizeof(SockInf)); /* 将SockInf[0]全部清零*/ SockInf.ProtoType = PROTO_TYPE_MAC_RAW; /* MAC RAW模式 */ } uint8_t CH395SocketInitOpen(void) { uint8_t i; /* socket 0为MAC RAW模式 */ CH395SetSocketProtType(CH395_SOCKET_INDEX,SockInf.ProtoType); /* 设置socket 0协议类型 */ i = CH395OpenSocket(CH395_SOCKET_INDEX); /* 打开socket 0 */ return i; } void CH395SocketInterrupt(uint8_t sockindex) { uint8_t sock_int_socket; uint16_t len; ch395_demo_manager_s *manager = &ch395_demo_manager; sock_int_socket = CH395GetSocketInt(sockindex); /* 获取socket 的中断状态 */ CH395_DEMO_LOG("ch395_sock_int_socket:0x%x",sock_int_socket); if(sock_int_socket & SINT_STAT_SENBUF_FREE) /* 发送缓冲区空闲,可以继续写入要发送的数据 */ { ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_DATA_OUTPUT,0,0,0); } if(sock_int_socket & SINT_STAT_SEND_OK) /* 发送完成中断 */ { //should be disabled } if(sock_int_socket & SINT_STAT_RECV) /* 接收中断 */ { len = CH395GetRecvLength(sockindex); /* 获取当前缓冲区内数据长度 */ CH395_DEMO_LOG("receive len = %d",len); if(len == 0) { return; } if(len > CH395_BUFFER_SIZE) { len = CH395_BUFFER_SIZE; } /*MyBuffer缓冲区长度为1514,*/ CH395GetRecvData(sockindex,len,MyBuffer); /* 读取数据 */ ql_ethernet_data_input(MyBuffer,len); } } void CH395GlobalInterrupt(void) { uint16_t init_status; uint8_t buf[10]; ch395_demo_manager_s *manager = &ch395_demo_manager; init_status = CH395CMDGetGlobIntStatus_ALL(); CH395_DEMO_LOG("ch395_init_status 0x%x",init_status); if(init_status & GINT_STAT_UNREACH) /* 不可达中断,读取不可达信息 */ { CH395CMDGetUnreachIPPT(buf); } if(init_status & GINT_STAT_IP_CONFLI) /* 产生IP冲突中断,建议重新修改CH395的 IP,并初始化CH395*/ { } if(init_status & GINT_STAT_PHY_CHANGE) /* 产生PHY改变中断*/ { CH395_DEMO_LOG("Init status : GINT_STAT_PHY_CHANGE\n"); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_STATUS_CHECK,0,0,0); } if(init_status & GINT_STAT_SOCK0) { CH395SocketInterrupt(0); /* 处理socket 0中断*/ } } uint8_t CH395Init(void) { CH395_DEMO_LOG("CH395init"); uint8_t i; i = CH395CMDCheckExist(0x65); if(i != 0x9a)return CH395_ERR_UNKNOW; /* 测试命令,如果无法通过返回0XFA */ /* 返回0XFA一般为硬件错误或者读写时序不对 */ i = CH395CMDInitCH395(); /* 初始化CH395芯片 */ return i; } void ch395_output(uint8_t * data,uint32_t len) { if(len > CH395_BUFFER_SIZE || len == 0) { CH395_DEMO_LOG("CH395_drop %d",len); return; } ch395_demo_manager_s *manager = &ch395_demo_manager; //Put packet to cache.And send it later ch395_try_lock(list_lock); bool send = false; if(ch395_list_is_empty(&list_header)) { send = true; } ch395_list_add_tail(&list_header,data,len); ch395_unlock(list_lock); CH395_DEMO_LOG("CH395_output,%d",send); if(true == send) { ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_DATA_OUTPUT,0,0,0); } } void _gpioint_cb(void *ctx) { ch395_demo_manager_s *manager = &ch395_demo_manager; //INT# from 1 to 0 ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_INT,0,0,0); CH395_DEMO_LOG("CH395_gpioint_cb"); } void ch395_app_reset(void) { ch395_demo_manager_s* manager = &ch395_demo_manager; ql_rtos_timer_stop(manager->timer); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_TRY_RESET,0,0,0); } ch395_app_gpio_cb_t ch395_app_get_gpio_cb(void) { return _gpioint_cb; } ch395_app_net_status_e ch395_app_net_status_get() { uint8_t status = CH395CMDGetPHYStatus(); uint8_t flag = PHY_DISCONN|PHY_10M_FLL|PHY_10M_HALF|PHY_100M_FLL|PHY_100M_HALF|PHY_AUTO; CH395_DEMO_LOG("ch395 get status %x",status); if(status == PHY_DISCONN) /* 查询CH395是否连接 */ { return CH395_APP_NET_DISCONNECTED; } else { if(status & (~(flag)) || (status & (status - 1)) != 0) { return CH395_APP_NET_NONE; } else { return CH395_APP_NET_CONNECTED; } } return CH395_APP_NET_NONE; } void ch395_app_net_status_notify(ch395_app_net_status_e status) { ch395_demo_manager_s* manager = &ch395_demo_manager; manager->status = status; if(manager->notify_cb) { manager->notify_cb(&status); } } static void ch395_app_net_status_cb(void* ctx) { ch395_demo_manager_s* manager = &ch395_demo_manager; ql_ethernet_net_status_e *pCtx = (ql_ethernet_net_status_e*)ctx; ch395_app_net_status_e status = CH395_APP_NET_NONE; /* IP is configured successfully. */ if(QL_ETHERNET_NET_STATUS_CONNECTED == *pCtx) { status = CH395_APP_NET_CONNECTED; } else if(QL_ETHERNET_NET_STATUS_DISCONNECTED == *pCtx) { status = CH395_APP_NET_DISCONNECTED; } if(status != manager->status) { ch395_app_net_status_notify(status); } } static void ch395_app_timer_cb(void *ctx) { ch395_demo_manager_s* manager = &ch395_demo_manager; CH395_DEMO_LOG("ch395 timer expired,id %x",manager->curr_id); if(manager->curr_id == QUEC_ETHERNET_DRV_TRY_RESET || manager->curr_id == QUEC_ETHERNET_DRV_TRY_CONNECT || manager->curr_id == QUEC_ETHERNET_DRV_STATUS_CHECK) { ch395_app_send_event(manager->task,manager->curr_id,0,0,0); } return; } void ch395_thread(void * arg) { ch395_demo_manager_s* manager = &ch395_demo_manager; ch395_create_mutex(&list_lock); ch395_create_mutex(&(manager->mutex)); /* Create a timer for status checking. */ int ret = ql_rtos_timer_create(&manager->timer, manager->task, ch395_app_timer_cb, NULL); if (ret != QL_OSI_SUCCESS) { CH395_DEMO_LOG("create timer ret: %x", ret); goto exit; } /* Try to reset the ch395. */ ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_TRY_RESET,0,0,0); while(1) { ql_event_t event; if(ql_event_try_wait(&event) != 0) { continue; } if (event.id == 0) { continue; } CH395_DEMO_LOG("ch395 read task event:%x",event.id); switch(event.id) { case QUEC_ETHERNET_DRV_TRY_RESET: { manager->curr_id = event.id; /* Notify reseting. */ ch395_app_net_status_notify(CH395_APP_NET_RESETING); /* Better add the hardware reset in reset callback. */ if(manager->reset_cb) { manager->reset_cb(NULL); } /* Try ch395 software reset. */ uint8_t i = 0; CH395CMDReset(); ql_rtos_task_sleep_ms(200); CH395SetStartPara(SOCK_DISABLE_SEND_OK_INT); i = CH395Init(); if(ch395_app_check_if_no_err(i)) { CH395_DEMO_LOG("ch395 try connect"); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_TRY_CONNECT,0,0,0); } break; } case QUEC_ETHERNET_DRV_TRY_CONNECT: { manager->curr_id = event.id; ch395_app_net_status_notify(CH395_APP_NET_CONNECTING); uint8_t i = 0; InitCH395InfParam(); /* 初始化CH395相关变量 */ InitSocketParam(); /* 初始化socket相关变量 */ i = CH395SocketInitOpen(); if(ch395_app_check_if_no_err(i)) { CH395_DEMO_LOG("ch395 check connect status"); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_STATUS_CHECK,0,0,0); } break; } case QUEC_ETHERNET_DRV_NET_CREATE: { ql_ethernet_errcode_e ret = 0; ql_ethernet_ctx_s ctx = { .ip4 = manager->ip4, .gw = manager->gw, .netmask = manager->netmask, .mac = manager->mac, .mode = manager->mode, .dns1 = manager->dns1, .dns2 = manager->dns2, /* This cb is used for receiving the ethernet data. */ .cb = ch395_output, /* This net_cb is used for receiving the ip configuration message. */ .net_cb = ch395_app_net_status_cb, }; bool err_flag = true; do { if(QL_ETHERNET_MODE_ROUTER == manager->mode) { if(manager->cover) { ctx.option.cover = manager->cover; /* Cid must be set in QL_ETHERNET_MODE_ROUTER mode. */ ctx.option.ecid.enable = true; ctx.option.ecid.sim_id = manager->sim_id; ctx.option.ecid.cid = manager->profile_idx; /* Set dhcp. */ ctx.option.dhcp = manager->dhcp; /* Set prefer. */ ctx.option.prefer = manager->prefer; } else { /* Cid must be set in QL_ETHERNET_MODE_ROUTER mode. */ ql_ethernet_cid_s cid = {.enable = true,.sim_id = manager->sim_id,.cid = manager->profile_idx}; ret = ql_ethernet_opt_set(QL_ETHERNET_OPT_CID,&cid,sizeof(ql_ethernet_cid_s)); if(QL_ETHERNET_SUCCESS != ret) { CH395_DEMO_LOG("opt set err %x",ret); break; } /* Set dhcp. */ ret = ql_ethernet_opt_set(QL_ETHERNET_OPT_DHCP,&manager->dhcp,sizeof(uint8_t)); if(QL_ETHERNET_SUCCESS != ret) { CH395_DEMO_LOG("opt set err %x",ret); break; } /* Set prefer. */ ql_ethernet_route_prefer_e prefer = manager->prefer; ret = ql_ethernet_opt_set(QL_ETHERNET_OPT_ROUTE_PREFER,&prefer,sizeof(ql_ethernet_route_prefer_e)); if(QL_ETHERNET_SUCCESS != ret) { CH395_DEMO_LOG("opt set err %x",ret); goto exit; } } } ret = ql_ethernet_register(&ctx); if(QL_ETHERNET_SUCCESS != ret && QL_ETHERNET_REPEAT_REGISTER_ERR != ret) { CH395_DEMO_LOG("net create err %x",ret); break; } err_flag = false; }while(0); if(err_flag) { /* Some error occurs.Sleep for while and try again. */ CH395_DEMO_LOG("err,try again"); ql_ethernet_deregister(); ql_rtos_task_sleep_ms(200); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_NET_CREATE,0,0,0); break; } ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_NET_UP,0,0,0); break; } case QUEC_ETHERNET_DRV_NET_UP: { ql_ethernet_set_up(); /* Wait for ch395_app_net_status_cb. Set CH395_APP_NET_CONNECTED/CH395_APP_NET_DISCONNECTED in it. */ break; } case QUEC_ETHERNET_DRV_NET_DOWN: { ql_ethernet_set_down(); ql_ethernet_deregister(); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_NET_CREATE,0,0,0); break; } case QUEC_ETHERNET_DRV_INT: { CH395GlobalInterrupt(); break; } case QUEC_ETHERNET_DRV_DATA_OUTPUT: { //Send one packet to SPI each time. ch395_try_lock(list_lock); if(!ch395_list_is_empty(&list_header)) { ch395_list_get_head(&list_header,SendBuffer,&SendBufferLen); CH395SendData(CH395_SOCKET_INDEX,(uint8_t*)SendBuffer,SendBufferLen); CH395_DEMO_LOG("ch395 packet %d sent",SendBufferLen); } ch395_unlock(list_lock); break; } case QUEC_ETHERNET_DRV_STATUS_CHECK: { manager->curr_id = QUEC_ETHERNET_DRV_STATUS_CHECK; ch395_app_net_status_e status = ch395_app_net_status_get(); CH395_DEMO_LOG("ch395 status %d",status); //Error status,try reset after reaching CH395_CHECK_STATUS_RESET_CNT times. if(status == CH395_APP_NET_NONE) { manager->status_reset_cnt++; if(manager->status_reset_cnt >= CH395_CHECK_STATUS_RESET_CNT) { manager->status_reset_cnt = 0; ql_rtos_timer_stop(manager->timer); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_TRY_RESET,0,0,0); CH395_DEMO_LOG("ch395 status read error at %d times,try reset",manager->status_reset_cnt); } break; } else { manager->status_reset_cnt = 0; } if((manager->status == CH395_APP_NET_CONNECTING || manager->status == CH395_APP_NET_DISCONNECTED) && status == CH395_APP_NET_CONNECTED) { ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_NET_DOWN,0,0,0); break; } //Keep checking status no matter connected or disconnect uint32_t check_time = (status == CH395_APP_NET_CONNECTED)?CH395_CONNECTED_CHECK_STATUS_TIME:CH395_CHECK_STATUS_TIME; CH395_DEMO_LOG("ch395 check time %ds",check_time/1000); ret = ql_rtos_timer_start(manager->timer, check_time, 0); if (ret != QL_OSI_SUCCESS) { CH395_DEMO_LOG("timer start failed"); ch395_app_send_event(manager->task,QUEC_ETHERNET_DRV_STATUS_CHECK,0,0,0); } //Only notify status to upper layer when status changes. if(manager->status != status) { CH395_DEMO_LOG("ch395 status from %d to %d",manager->status,status); ch395_app_net_status_notify(status); } break; } default: { break; } } } exit: ch395_delete_mutex(list_lock); ch395_app_deinit(NULL); } bool ch395_app_cb_register(ch395_app_cb_type_e type,void* cb) { if(type >= CH395_APP_CB_TYPE_MAX) { return false; } ch395_demo_manager_s* manager = &ch395_demo_manager; switch(type) { case CH395_APP_CB_TYPE_RESET: { manager->reset_cb = cb; break; } case CH395_APP_CB_TYPE_NOTIFY: { manager->notify_cb = cb; break; } default:break; } return true; } bool ch395_app_init(void* argv) { ql_ethernet_ctx_s *ctx = (ql_ethernet_ctx_s*)argv; bool ret = false; if(!ctx) { CH395_DEMO_LOG("ctx null"); goto exit; } ch395_demo_manager_s* manager = &ch395_demo_manager; uint8_t def_ip4[4] = {192,168,1,100}; uint8_t def_gw[4] = {192,168,1,0}; uint8_t def_netmask[4] = {255,255,255,0}; uint8_t def_dns1[4] = {8,8,8,8}; uint8_t def_dns2[4] = {114,114,114,114}; /* Set ip. */ memcpy((void*)(manager->ip4),(NULL == ctx->ip4)?def_ip4:ctx->ip4,sizeof(manager->ip4)); /* Set gw. */ memcpy((void*)(manager->gw),(NULL == ctx->gw)?def_gw:ctx->gw,sizeof(manager->gw)); /* Set netmask. */ memcpy((void*)(manager->netmask),(NULL == ctx->netmask)?def_netmask:ctx->netmask,sizeof(manager->netmask)); /* No need to set mac.If we do want to change the mac of CH395,set in InitCH395InfParam. */ memset((void*)(manager->mac),0,sizeof(manager->mac)); /* Set dns. If no dns parameter,set default dns. */ memcpy((void*)(manager->dns1),(NULL == ctx->dns1)? def_dns1:ctx->dns1,sizeof(manager->dns1)); memcpy((void*)(manager->dns2),(NULL == ctx->dns2)? def_dns2:ctx->dns2,sizeof(manager->dns2)); /* Set mode. */ if(ctx->mode < QL_ETHERNET_MODE_MAX) { manager->mode = ctx->mode; /* Set the necessary parameters except for QL_ETHERNET_MODE_NONE. */ if(QL_ETHERNET_MODE_NONE != manager->mode) { manager->cover = ctx->option.cover? 1 : 0; manager->dhcp = ctx->option.dhcp ? 1 : 0; manager->prefer = ctx->option.prefer; manager->sim_id = ctx->option.ecid.sim_id; manager->profile_idx = ctx->option.ecid.cid; } } else { CH395_DEMO_LOG("mode err"); goto exit; } QlOSStatus err = QL_OSI_SUCCESS; err = ql_rtos_task_create(&(manager->task), 8*1024, APP_PRIORITY_REALTIME, "ch395_task", ch395_thread, NULL, 100); if(err != QL_OSI_SUCCESS) { CH395_DEMO_LOG("task created failed"); goto exit; } ret = true; exit: return ret; } bool ch395_app_deinit(void* argv) { ch395_demo_manager_s* manager = &ch395_demo_manager; ch395_demo_manager_s cmp = {0}; if(0 != memcmp(manager,&cmp,sizeof(ch395_demo_manager_s))) { ql_ethernet_deregister(); if(manager->timer) { ql_rtos_timer_delete(manager->timer); } if(manager->task) { ql_rtos_task_delete(manager->task); manager->task = NULL; } memset(manager,0,sizeof(ch395_demo_manager_s)); CH395CMDSleep(); } else { CH395_DEMO_LOG("ch395 already deinit"); } return true; }