EC600U_esp32_iap_uart/EC600U_uart1/download.c

441 lines
13 KiB
C
Raw Permalink Normal View History

2024-02-05 17:39:56 +08:00
#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);
}