EC600U_esp32_iap_uart/EC600U_uart1/download.c
2024-02-05 17:39:56 +08:00

441 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sockets.h"
#include "ql_fs.h"
#include "ql_api_datacall.h"
#include "ql_api_osi.h"
#include "ql_http_client.h"
#include "ql_log.h"
#define LOGI(msg, ...) QL_LOG(QL_LOG_LEVEL_INFO, "download", msg, ##__VA_ARGS__)
#define SIM_ID (0)
#define NETWORK_REGISTER_RETRY (10)
#define NETWORK_REGISTER_TIMEOUT (120)
#define NETWORK_PROFILE_IDX (1)
#define NETWORK_APN_NAME "uninet"
#define NETWORK_AUTH_TYPE (0) // 表示不进行身份验证
#define HTTP_DLOAD_HIGH_LINE (40960)
#define HTTP_MAX_MSG_CNT (8)
#define DOWNLOAD_FILENAME "SD:test.txt"
#define USE_HTTP_URL (1)
#define HTTP_URL "http://220.180.239.212:8300/10K.txt"
#define USE_HTTPS_URL (0)
#define HTTPS_URL "https://220.180.239.212:8301/10K.txt"
typedef enum
{
QHTTPC_EVENT_RESPONSE = 1001,
QHTTPC_EVENT_END,
} qhttpc_event_code_e;
typedef struct _qhttpc_ctx_t
{
http_client_t http_client;
ql_queue_t queue;
ql_mutex_t simple_lock;
bool dl_block;
int dl_high_line;
int dl_total_len;
QFILE dload_fd;
} qhttpc_ctx_t;
static ql_datacall_errcode_e network_err = QL_DATACALL_SUCCESS;
static QlOSStatus status = 0;
void print_info(ql_data_call_info_s info);
/*http状态事件回调*/
static void http_event_cb(http_client_t *client, int evt, int evt_code, void *arg)
{
qhttpc_ctx_t *client_ptr = (qhttpc_ctx_t *)arg;
ql_event_t qhttpc_event_send = {0};
LOGI("enter");
if (client_ptr == NULL)
return;
LOGI("*client:%d, http_cli:%d", *client, client_ptr->http_client);
if (*client != client_ptr->http_client)
return;
LOGI("evt:%d, evt_code:%d", evt, evt_code);
switch (evt)
{
case HTTP_EVENT_SESSION_ESTABLISH:
{
if (evt_code != HTTP_SUCCESS)
{
LOGI("HTTP session create failed!!!!!");
qhttpc_event_send.id = QHTTPC_EVENT_END;
qhttpc_event_send.param1 = (uint32)client_ptr;
ql_rtos_queue_release(client_ptr->queue, sizeof(ql_event_t), (uint8 *)&qhttpc_event_send, QL_WAIT_FOREVER);
}
}
break;
case HTTP_EVENT_RESPONE_STATE_LINE:
{
if (evt_code == HTTP_SUCCESS)
{
int resp_code = 0;
int content_length = 0;
int chunk_encode = 0;
char *location = NULL;
ql_httpc_getinfo(client, HTTP_INFO_RESPONSE_CODE, &resp_code);
LOGI("response code:%d", resp_code);
ql_httpc_getinfo(client, HTTP_INFO_CHUNK_ENCODE, &chunk_encode);
if (chunk_encode == 0)
{
ql_httpc_getinfo(client, HTTP_INFO_CONTENT_LEN, &content_length);
LOGI("content_length:%d", content_length);
}
else
{
LOGI("http chunk encode!!!");
}
if (resp_code >= 300 && resp_code < 400)
{
ql_httpc_getinfo(client, HTTP_INFO_LOCATION, &location);
LOGI("redirect location:%s", location);
free(location);
}
}
}
break;
case HTTP_EVENT_SESSION_DISCONNECT:
{
if (evt_code == HTTP_SUCCESS)
{
LOGI("===http transfer end!!!!");
}
else
{
LOGI("===http transfer occur exception!!!!!");
}
qhttpc_event_send.id = QHTTPC_EVENT_END;
qhttpc_event_send.param1 = (uint32)client_ptr;
ql_rtos_queue_release(client_ptr->queue, sizeof(ql_event_t), (uint8 *)&qhttpc_event_send, QL_WAIT_FOREVER);
}
break;
}
}
/*http写入响应数据的回调*/
static int http_write_response_data(http_client_t *client, void *arg, char *data, int size, unsigned char end)
{
int ret = size;
uint32 msg_cnt = 0;
char *read_buff = NULL;
qhttpc_ctx_t *client_ptr = (qhttpc_ctx_t *)arg;
ql_event_t qhttpc_event_send = {0};
LOGI("enter");
if (client_ptr == NULL)
return 0;
LOGI("*client:%d, http_cli:%d", *client, client_ptr->http_client);
if (*client != client_ptr->http_client)
return 0;
read_buff = (char *)malloc(size + 1);
if (read_buff == NULL)
{
LOGI("mem faild");
return 0;
}
memcpy(read_buff, data, size);
if (QL_OSI_SUCCESS != ql_rtos_queue_get_cnt(client_ptr->queue, &msg_cnt))
{
free(read_buff);
LOGI("ql_rtos_queue_get_cnt faild");
return 0;
}
ql_rtos_mutex_lock(client_ptr->simple_lock, 100);
if (msg_cnt >= (HTTP_MAX_MSG_CNT - 1) || (client_ptr->dl_total_len + size) >= client_ptr->dl_high_line)
{
client_ptr->dl_block = true;
ret = HTTP_ERR_WOUNDBLOCK;
}
ql_rtos_mutex_unlock(client_ptr->simple_lock);
LOGI("msg_cnt %d, total_len+size %d", msg_cnt, (client_ptr->dl_total_len + size));
qhttpc_event_send.id = QHTTPC_EVENT_RESPONSE;
qhttpc_event_send.param1 = (uint32)client_ptr;
qhttpc_event_send.param2 = (uint32)read_buff;
qhttpc_event_send.param3 = (uint32)size;
if (QL_OSI_SUCCESS != ql_rtos_queue_release(client_ptr->queue, sizeof(ql_event_t), (uint8 *)&qhttpc_event_send, 0))
{
free(read_buff);
LOGI("ql_rtos_queue_release faild");
return 0;
}
ql_rtos_mutex_lock(client_ptr->simple_lock, 100);
client_ptr->dl_total_len += size;
ql_rtos_mutex_unlock(client_ptr->simple_lock);
LOGI("http response :%d bytes data", size);
return ret;
}
static void http_write_response_data_func(void *param)
{
int ret = 0;
int size = 0;
QFILE fd = 0;
bool dload_block = false;
char *read_buff = NULL;
qhttpc_ctx_t *client_ptr = NULL;
ql_event_t *qhttpc_event_recv = (ql_event_t *)param;
if(qhttpc_event_recv == NULL || qhttpc_event_recv->param1 == 0 || qhttpc_event_recv->param2 == 0 || qhttpc_event_recv->param3 == 0)
return;
client_ptr = (qhttpc_ctx_t *)qhttpc_event_recv->param1;
read_buff = (char *)qhttpc_event_recv->param2;
size = (int)qhttpc_event_recv->param3;
fd = (QFILE)client_ptr->dload_fd;
ret = ql_fwrite(read_buff, size, 1, fd);
free(read_buff);
ql_rtos_mutex_lock(client_ptr->simple_lock, 100);
client_ptr->dl_total_len -= size;
if(client_ptr->dl_total_len < 0)
client_ptr->dl_total_len = 0;
if(client_ptr->dl_block == true && client_ptr->dl_total_len < client_ptr->dl_high_line)
{
dload_block = client_ptr->dl_block;
client_ptr->dl_block = false;
}
ql_rtos_mutex_unlock(client_ptr->simple_lock);
if(dload_block == true)
ql_httpc_continue_dload(&client_ptr->http_client);
LOGI("http write :%d bytes data", ret);
}
/**
* func:从http下载文件到本地SD卡中
*/
uint8_t download_file_to_SD(void)
{
LOGI("download_file_to_SD start");
uint8_t nSim = 0;
int profile_idx = NETWORK_PROFILE_IDX;
/*等待网络注册*/
for (uint8_t i = 0; i < 10; i++)
{
LOGI("ql_network_register_wait err = %d", ql_network_register_wait(nSim, 120));
ql_rtos_task_sleep_s(1);
}
LOGI("ql_network_register_wait end");
/*设置ql_start_data_call和ql_stop_data_call接口的执行模式并设置异步模式的回调函数*/
network_err = ql_set_data_call_asyn_mode(nSim, profile_idx, 0);
if (network_err != 0)
{
LOGI("ql_set_data_call_asyn_mode fail,err = %d", network_err);
return 2;
}
LOGI("ql_set_data_call_asyn_mode ok");
/*启动拨号*/
network_err = ql_start_data_call(nSim, profile_idx, QL_PDP_TYPE_IP, NETWORK_APN_NAME, NULL, NULL, NETWORK_AUTH_TYPE);
if (network_err != 0)
{
LOGI("ql_start_data_call fail,err = %d", network_err);
return 3;
}
LOGI("ql_start_data_call ok");
/*获取拨号信息*/
ql_data_call_info_s info = {0};
network_err = ql_get_data_call_info(nSim, profile_idx, &info);
if (network_err != 0)
{
LOGI("ql_get_data_call_info fail,err = %d", network_err);
return 4;
}
LOGI("ql_get_data_call_info ok");
/*打印拨号信息*/
print_info(info);
/*初始化http客户端结构体*/
qhttpc_ctx_t http_demo_client = {0};
http_demo_client.dl_block = false;
http_demo_client.dl_high_line = HTTP_DLOAD_HIGH_LINE;
/*创建互斥锁*/
status = ql_rtos_mutex_create(&http_demo_client.simple_lock);
if (status != 0)
{
LOGI("ql_rtos_mutex_create fail,err = %d", network_err);
return 5;
}
LOGI("ql_rtos_mutex_create ok");
/*创建消息队列*/
status = ql_rtos_queue_create(&http_demo_client.queue, sizeof(ql_event_t), HTTP_MAX_MSG_CNT);
if (status != 0)
{
LOGI("ql_rtos_queue_create fail,err = %d", network_err);
return 6;
}
LOGI("ql_rtos_queue_create ok");
/*创建并初始化http_client上下文结构*/
if (ql_httpc_new(&http_demo_client.http_client, http_event_cb, (void *)&http_demo_client) != HTTP_SUCCESS)
{
LOGI("http client create failed");
return 7;
}
LOGI("http client create ok");
/*写模式打开文件*/
http_demo_client.dload_fd = ql_fopen(DOWNLOAD_FILENAME, "w+");
if (http_demo_client.dload_fd < 0)
{
LOGI("open file failed");
ql_httpc_release(&http_demo_client.http_client);
return 8;
}
/*配置http上下文*/
int http_method = HTTP_METHOD_NONE;
int a = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_SIM_ID, nSim);
int b = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_PDPCID, profile_idx);
int c = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_WRITE_FUNC, http_write_response_data);
int d = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_WRITE_DATA, (void *)&http_demo_client);
if ((a != 0) || (b != 0) || (c != 0) || (d != 0))
{
LOGI("ql_httpc_setopt fail, a = %d, b = %d, c = %d, d = %d", a, b, c, d);
return 9;
}
LOGI("ql_httpc_setopt 1 ok");
#if USE_HTTP_URL
http_method = HTTP_METHOD_GET;
char url[] = HTTP_URL;
int e = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_METHOD, http_method);
int f = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_URL, (char *)url);
if ((e != 0) || (f != 0))
{
LOGI("ql_httpc_setopt fail, e = %d, f = %d", e, f);
return 10;
}
LOGI("ql_httpc_setopt 2 ok");
#endif
#if USE_HTTPS_URL
char url[] = HTTPS_URL;
http_method = HTTP_METHOD_GET;
ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_METHOD, http_method);
ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_SSLCTXID, 1);
ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_SSL_VERIFY_LEVEL, HTTPS_VERIFY_NONE);
ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_URL, (char *)url);
#endif
/*关联http client此上下文和http的读写回调函数*/
if (ql_httpc_perform(&http_demo_client.http_client) != HTTP_SUCCESS)
{
LOGI("ql_httpc_perform fail");
return 11;
}
LOGI("ql_httpc_perform ok");
/*等待事件完成*/
int flags_break = 0;
ql_event_t qhttpc_event_msg = {0};
for (;;)
{
memset(&qhttpc_event_msg, 0x00, sizeof(ql_event_t));
ql_rtos_queue_wait(http_demo_client.queue, (uint8 *)&qhttpc_event_msg, sizeof(ql_event_t), QL_WAIT_FOREVER);
switch (qhttpc_event_msg.id)
{
case QHTTPC_EVENT_RESPONSE:
{
http_write_response_data_func((void *)&qhttpc_event_msg);
}
break;
case QHTTPC_EVENT_END:
{
flags_break = 1;
}
break;
default:
break;
}
if (flags_break)
break;
}
LOGI("event end");
/*检测文件状态*/
struct stat dload_stat = {0};
memset(&dload_stat, 0x00, sizeof(struct stat));
ql_fstat(http_demo_client.dload_fd, &dload_stat);
LOGI("dload_file_size:%d", dload_stat.st_size);
if (http_demo_client.dload_fd >= 0)
{
ql_fclose(http_demo_client.dload_fd);
http_demo_client.dload_fd = -1;
}
/*释放http client上下文,以及http client上下文所占用内存块*/
if(ql_httpc_release(&http_demo_client.http_client) != 0){
LOGI("ql_httpc_release fail");
return 12;
}
http_demo_client.http_client = 0;
LOGI("ql_httpc_release ok");
/*解锁互斥锁*/
status = ql_rtos_mutex_delete(http_demo_client.simple_lock);
if(status != 0){
LOGI("ql_rtos_mutex_delete fail,err = %d",status);
return 13;
}
http_demo_client.simple_lock = NULL;
LOGI("ql_rtos_mutex_delete ok");
LOGI("download_file_to_SD end");
return 0;
}
void print_info(ql_data_call_info_s info)
{
char ip4_addr_str[16] = {0};
LOGI("info->profile_idx: %d", info.profile_idx);
LOGI("info->ip_version: %d", info.ip_version);
LOGI("info->v4.state: %d", info.v4.state);
inet_ntop(AF_INET, &info.v4.addr.ip, ip4_addr_str, sizeof(ip4_addr_str));
LOGI("info.v4.addr.ip: %s\r\n", ip4_addr_str);
inet_ntop(AF_INET, &info.v4.addr.pri_dns, ip4_addr_str, sizeof(ip4_addr_str));
LOGI("info.v4.addr.pri_dns: %s\r\n", ip4_addr_str);
inet_ntop(AF_INET, &info.v4.addr.sec_dns, ip4_addr_str, sizeof(ip4_addr_str));
LOGI("info.v4.addr.sec_dns: %s\r\n", ip4_addr_str);
}