首先感谢B站up主小智-学长提供的优质开源项目并且还有详细的视频、文档教学。视频教学包括硬件设计、软件设计和外壳结构的设计,视频的链接如下:
【有手就行系列】嵌入式单片机教程-桌面小屏幕实战教学 从设计、硬件、焊接到代码编写、调试 ESP32 持续更新2022【有手就行系列】嵌入式单片机教程-桌面小屏幕实战教学 从设计、硬件、焊接到代码编写、调试 ESP32 持续更新2022_哔哩哔哩_bilibili
其中freertos的一些内容参考了这篇文章:(45条消息) FreeRTOS系列第18篇---FreeRTOS队列API函数_研究是为了理解的博客-CSDN博客,博主关于freertos系列的文章都很棒,有兴趣的朋友可以学习下。
DesktopScreenDemoV4.0.0的源码可以在小智学长的线上文档中下载到Docs (feishu.cn)。
此文主要用于个人学习成果的检验,如果能帮助到像我一样的初学者那就更好了。如果有理解错的或者写得不够好的地方,希望各位大佬不吝赐教,小弟一定虚心学习!
DesktopScreenDemoV4.0.0 app_main.c文件中对桌面小屏幕的功能实现用到了三个函数,所以我计划把项目代码分成三篇文章来进行分享,主要分成三个部分,sleep_mode_init()函数、background_task(void* arg)函数和app_main函数。这一节与大家一起学习的是app_main函数的内容。
app_main函数是DesktopScreen的主函数,因为函数内容过多,我将分成多篇文章来分享。
本篇文章介绍的是http请求初始化函数。
![](https://img-blog.csdnimg.cn/img_convert/786c12569ba01b1b292e81462c3d1a0f.png)
http请求初始化,初始化函数中创建了http_request_task任务函数,函数原型如下:
void ds_http_request_init(void)
{
http_request_event_queue = xQueueCreate(10, sizeof(HTTP_REQUEST_TYPE_E)); 1.
xTaskCreate(&http_request_task, "http_request_task", 4096, NULL, 5, NULL);
}
static void http_request_task(void *pvParameters)
{
while(1) {
HTTP_REQUEST_TYPE_E evt; 2.
xQueueReceive(http_request_event_queue, &evt, portMAX_DELAY); 3.
ESP_LOGI(TAG, "http_get_task %d",evt);
vTaskDelay(1000 / portTICK_PERIOD_MS);
switch (evt)
{
case HTTP_GET_TIME:
http_time_get(); 4.
break;
case HTTP_GET_WEATHER:
http_weather_get(); 5.
break;
case HTTP_GET_FANS:
http_fans_get(); 6.
break;
case HTTP_GET_CITY:
http_city_get(); 7.
break;
default:
break;
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
1创建大小为10个项目的队列,每个项目占用的空间为HTTP_REQUEST_TYPE_E枚举的内存大小。
2HTTP_REQUEST_TYPE_E是一个枚举名,枚举用于设置http获取的内容类型。分别为时钟、天气、粉丝、城市。
typedef enum{
HTTP_GET_TIME =0,
HTTP_GET_WEATHER,
HTTP_GET_FANS,
HTTP_GET_CITY,
}HTTP_REQUEST_TYPE_E;
3获取队列项目,此函数不能在中断中使用,打印获取到的任务的信息,延时1s。
4.获取时钟信息。函数原型如下:
void http_time_get(){
//http client配置
esp_http_client_config_t config = { 4.1
.method = HTTP_METHOD_GET, //get请求
.url = "http://quan.suning.com/getSysTime.do", 4.2
.event_handler = _http_time_event_handle, 4.3 //注册时间回调
.skip_cert_common_name_check = true, 4.4
};
esp_http_client_handle_t time_client = esp_http_client_init(&config); 4.5 //初始化配置
esp_err_t err = esp_http_client_perform(time_client); 4.6 //执行请求
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Status = %d, content_length = %d", 4.7
esp_http_client_get_status_code(time_client), //状态码
esp_http_client_get_content_length(time_client)); //数据长度
}
esp_http_client_cleanup(time_client); 4.8 //断开并释放资源
}
4.1http配置结构体,结构体成员有很多,这里只用到了4个,详细信息见esp_http_client.h文件。.method用于配置http的运行方式,HTTP_METHOD_GET是HTTP method的枚举成员,里面包含更多的http运行方式详细见esp_http_client.h。
4.2..url配置http获取时钟信息的URL(在WWW上,每一信息资源都有统一的且在网上的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位器),它是WWW的统一资源定位标志,就是指网络地址。)我们通过此网址获取当前系统的时间。
4.3.event_handler为事件句柄,注册时间回调函数。
//事件回调
static esp_err_t _http_time_event_handle(esp_http_client_event_t *evt)
{
static char* output_buffer; 4.3.1 // Buffer to store response of http request from event handler
static int output_len; 4.3.2 // Stores number of bytes read
switch(evt->event_id) {
case HTTP_EVENT_ON_DATA: //接收数据事件
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) { 4.3.3
if (output_buffer == NULL) {
output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
output_len = 0;
if (output_buffer == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
return ESP_FAIL;
}
}
memcpy(output_buffer + output_len, evt->data, evt->data_len); 4.3.4
printf("%.*s\n", output_len, output_buffer);
cjson_time_info((char*)output_buffer); 4.3.5
output_len += evt->data_len;
}
break;
case HTTP_EVENT_ERROR:
break;
case HTTP_EVENT_ON_CONNECTED:
break;
case HTTP_EVENT_HEADERS_SENT:
break;
case HTTP_EVENT_ON_HEADER:
break;
case HTTP_EVENT_ON_FINISH: 4.3.6
ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
if (output_buffer != NULL) {
// Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
// ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
free(output_buffer);
output_buffer = NULL;
}
output_len = 0;
break;
case HTTP_EVENT_DISCONNECTED: 4.3.7
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
int mbedtls_err = 0;
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
if (err != 0) {
ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
}
if (output_buffer != NULL) {
free(output_buffer);
output_buffer = NULL;
}
output_len = 0;
break;
}
return ESP_OK;
}
4.3.1存储事件处理器的hhtp请求响应缓冲区。
4.3.2存储读取的字节长度。
4.3.3调用API函数判断响应数据是否为块,如果不是,继续执行下列代码。如果存储响应请求的缓冲区为空,则手动为其分配内存,并清空存储读取的字节长度。最后判断缓冲区是否仍然为空,如果还是空的话打印分配缓冲区内存失败的日志信息。
4.3.4将事件数据evt->data拷贝到output_buffer缓冲区+output_len的存储位置。
4.3.5使用cjson解析获取的时钟信息,关于cjson的详细内容参考以下文章的内容:http://t.csdn.cn/aKnc8。函数原型如下:
/*exmaple
{
"sysTime2":"2022-07-10 10:12:43",
"sysTime1":"20220710101243"
}
*/
static void cjson_time_info(char *text)
{
cJSON *root,*psub;
char time[20];
//截取有效jso
char *index=strchr(text,'{');
strcpy(text,index);
root = cJSON_Parse(text);
if(root!=NULL)
{
psub = cJSON_GetObjectItem(root, "sysTime1");
sprintf(time,"%s",psub->valuestring);
ESP_LOGI(TAG,"sysTime:%s",time);
}
cJSON_Delete(root);
int len = strlen(time);
if(len < 11){
return;
}
uint8_t hour;
uint8_t minute;
uint8_t second;
hour = (time[8] - '0')*10+time[9] - '0';
minute = (time[10] - '0')*10+time[11] - '0';
second = (time[12] - '0')*10+time[13] - '0';
update_system_time(hour,minute,second); //根据获取的时间更新系统时间。
}
4.3.6完成http会话时,打印日志信息,假如缓冲区中还有数据占用空间,则释放缓冲区内存,标志为空。
4.3.7http连接断开时,打印日志信息。调用esp_tls_get_and_clear_last_error函数获取esp_tls中的最后一个错误以及详细的mbedtls相关错误代码,打印错误信息。最后判断缓冲区是否为空,如果非空则释放内存空间,设置标志位为空。函数原型如下:
esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *esp_tls_code, int *esp_tls_flags);
4.4跳过服务器证书CN字段的任何验证。
4.5初始化http。这个函数必须作为第一个调用的函数,它返回一个esp_http_client_handle_t句柄作为其他函数接口的输入。当操作完成后,必须调用相应的esp_http_client_cleanup函数。
4.6在调用esp_http_client_handle_t函数和所有选项调用完成后,调用此函数执行请求。
4.7调用API函数获取状态码和数据长度打印到消息日志上。
4.8断开并释放资源,当操作完成后,必须调用相应的esp_http_client_cleanup函数。
5.获取天气信息。函数原型如下:
void http_weather_get(){
char count_url[130];
char *city = ds_nvs_read_city(); 5.1
//判断是否有存储城市信息
if(city != NULL){
char url[] = "http://api.seniverse.com/v3/weather/now.json?key=SmazqPcltzTft-X3v&location="; 5.2
uint8_t city_len = strlen(city); 5.3
char citydata[30];
memcpy(citydata,city,city_len);
citydata[city_len] = '\0';
strcat(url,citydata);
strcat(url,"&language=zh-Hans&unit=c");
printf("%s\n",url);
strcpy(count_url,url);
free(city);
}else{
strcpy(count_url,"http://api.seniverse.com/v3/weather/now.json?key=SmazqPcltzTft-X3v&location=guangzhou&language=zh-Hans&unit=c"); 5.4
}
//http client配置
esp_http_client_config_t config = {
.method = HTTP_METHOD_GET, 5.5 //get请求
.url = count_url, 5.6
.event_handler = _http_weather_event_handle, 5.7 //注册时间回调
.skip_cert_common_name_check = true, 5.8
};
esp_http_client_handle_t weather_client = esp_http_client_init(&config); 5.9 //初始化配置
esp_err_t err = esp_http_client_perform(weather_client); 5.10 //执行请求
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Status = %d, content_length = %d", 5.11
esp_http_client_get_status_code(weather_client),//状态码
esp_http_client_get_content_length(weather_client));//数据长度
}
esp_http_client_cleanup(weather_client); 5.12 //断开并释放资源
}
5.1读取NVS中的城市信息。函数原型如下:
char * ds_nvs_read_city(){
esp_err_t err;
nvs_handle_t nvs_handle;
err = nvs_open("cityconfig", NVS_READWRITE, &nvs_handle); 5.1.1
if (err != ESP_OK) {
ESP_LOGI(TAG,"Error (%s) opening NVS handle!\n", esp_err_to_name(err));
return NULL;
}
size_t city_len;
if ( (err = nvs_get_str(nvs_handle, "city", NULL, &city_len)) == ESP_OK) { 5.1.2
char *city = (char *)malloc(city_len); 5.1.3
if ( (err = nvs_get_str(nvs_handle, "city", city, &city_len)) == ESP_OK) { 5.1.4
printf("city = %s\n", city);
nvs_close(nvs_handle);
return city;
}
}
nvs_close(nvs_handle);
return NULL;
}
5.1.1通过给定命名空间,从默认NVS分区中打开指定NVS存储区域。参数说明:name:空间命名,最大长度为(NVS_KEY_NAME_MAX_SIZE-1) 个字符,不能为空。open_mode:打开方式,可设置读写或者只读模式,如果为只读模式将打开只读句柄,所有写请求将被此句柄拒绝。out_handle:如果打开成功(返回值为0),句柄将通过此参数返回。如果打开失败,将打印相应的错误日志信息。函数原型如下:
esp_err_t nvs_open(const char* name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle);
5.1.2通过给定密钥获取字符串值,成功获取则返回ESP_OK。参数说明:handle:从nvs_open函数获得的句柄;key:密钥名称,最大长度为(NVS_KEY_NAME_MAX_SIZE-1) 个字符,不能为空; out_value:指向输出值的指针,对于nvs_get_str和nvs_get_blob,可能为NULL,在这种情况下,所需的长度将在长度参数中返回;length:指向保存out_value长度变量的非零指针。如果out_value为零,则将设置为保持该值所需的长度。如果out_value非零,则将设置为写入值的实际长度,调用nvs_get_str时这包含\'0'字符。
函数原型如下:
esp_err_t nvs_get_str (nvs_handle_t handle, const char* key, char* out_value, size_t* length);
5.1.3创建一个指向char类型的指针,并为它分配内存空间。
5.1.4通过给定密钥获取字符串值,成功获取则返回ESP_OK。然后打印获取到的city信息,关闭NVS,最后返回city信息。
5.3判断是否存储了城市信息,如果有则将其通过库函数进行一系列拷贝和补充的方式,补充到缺少城市信息的URL上(C库函数详细信息可参考:菜鸟教程 - 学的不仅是技术,更是梦想! (runoob.com))
5.4将获取城市信息的URL拷贝到count_url数组中。
5.5.method用于配置http的运行方式,这里配置为获取请求,HTTP_METHOD_GET是HTTP method的枚举成员,里面包含更多的http运行方式详细见esp_http_client.h。
5.6.url配置http获取天气信息的URL(在WWW上,每一信息资源都有统一的且在网上的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位器),它是WWW的统一资源定位标志,就是指网络地址。)我们通过此网址获取当前系统的时间。
5.7.event_handler为事件句柄,注册回调函数。
static esp_err_t _http_weather_event_handle(esp_http_client_event_t *evt)
{
static char* output_buffer; 5.7.1 // Buffer to store response of http request from event handler
static int output_len; 5.7.2 // Stores number of bytes read
switch(evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADERS_SENT:
ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA: 5.7.3
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
/*
* Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
* However, event handler can also be used in case chunked encoding is used.
*/
if (!esp_http_client_is_chunked_response(evt->client)) { 5.7.4
// If user_data buffer is configured, copy the response into the buffer
if (evt->user_data) { 5.7.5
memcpy(evt->user_data + output_len, evt->data, evt->data_len);
printf("%.*s\n", output_len, (char*)evt->user_data);
cjson_weather_info((char*)evt->user_data); 5.7.6
} else {
if (output_buffer == NULL) { 5.7.7
output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
output_len = 0;
if (output_buffer == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
return ESP_FAIL;
}
}
memcpy(output_buffer + output_len, evt->data, evt->data_len); 见5.7.5
printf("%.*s\n", output_len, output_buffer);
cjson_weather_info((char*)output_buffer); 见5.7.6
}
output_len += evt->data_len;
}
break;
case HTTP_EVENT_ON_FINISH: 5.7.8
ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
if (output_buffer != NULL) {
// Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
// ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
free(output_buffer);
output_buffer = NULL;
}
output_len = 0;
break;
case HTTP_EVENT_DISCONNECTED: 5.7.9
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
int mbedtls_err = 0;
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
if (err != 0) {
ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
}
if (output_buffer != NULL) {
free(output_buffer);
output_buffer = NULL;
}
output_len = 0;
break;
}
return ESP_OK;
}
5.7.1存储事件处理器的hhtp请求响应缓冲区。
5.7.2存储读取的字节长度。
5.7.3如果http事件是在服务器接收数据时发送
5.7.4检查响应数据是否不为块。
5.7.5如果配置好了user_data缓冲区,则将响应数据拷贝到缓冲区中。
5.7.6使用cjson解析获取到的天气信息,关于cjson的详细内容参考以下文章的内容:http://t.csdn.cn/aKnc8。解析函数中有一个设置天气相关信息的函数,简单说一下:cjson解析函数内部将获取到的城市名、天气、代码数、温度信息作为参数传递给这个函数,函数内部将这些信息存储到设置天气界面的结构体当中,g_weather_page是WEATHER_PAGE_T的结构体变量。
void ds_ui_weather_set(VALUE_TYPE_T type,char *value){
if(type == VALUE_CITY)
sprintf(g_weather_page.city,"%s",value);
else if(type == VALUE_WEATHER)
sprintf(g_weather_page.weather_text,"%s",value);
else if(type == VALUE_CODE)
sprintf(g_weather_page.weather_code,"%s",value);
else if(type == VALUE_TEMP)
sprintf(g_weather_page.temperature_array,"%s",value);
if(strlen(g_weather_page.weather_code) == 2)
g_weather_page.code = (g_weather_page.weather_code[1] - '0')*10+g_weather_page.weather_code[0] - '0';
else
g_weather_page.code = g_weather_page.weather_code[0] - '0';
// printf("value:%s code:%d",value,g_weather_page.code);
}
typedef struct
{
uint8_t init_status;
uint8_t updateing;
//0-3晴 4-8多云 9-阴 10-13-小雨 14-19暴雨 20-25雪 >26 大风
uint8_t code;
char city[20];
char weather_text[20];
char weather_code[2];
char temperature_array[3];
}WEATHER_PAGE_T;
5.7.7如果user_data缓冲区没有被配置同时输出缓冲区判断为空,为它分配内存空间。
5.7.8当事件完成时,释放缓冲区内存。
5.7.9见4.3.7
5.8跳过服务器证书CN字段的任何验证。
5.9初始化http。这个函数必须作为第一个调用的函数,它返回一个esp_http_client_handle_t句柄作为其他函数接口的输入。当操作完成后,必须调用相应的esp_http_client_cleanup函数。
5.10在调用esp_http_client_handle_t函数和所有选项调用完成后,调用此函数执行请求。
5.11调用API函数获取状态码和数据长度打印到消息日志上。
5.12断开并释放资源,当操作完成后,必须调用相应的esp_http_client_cleanup函数。
6.获取粉丝信息。函数原型如下:
void http_fans_get(){
char url[100];
if(fans_type == 0){ 6.1
//小智
strcpy(url,"http://api.bilibili.com/x/relation/stat?vmid=383943678&jsonp=jsonp");
}else{
//阿奇
strcpy(url,"http://api.bilibili.com/x/relation/stat?vmid=257459324&jsonp=jsonp");
}
//http client配置
esp_http_client_config_t config = {
.method = HTTP_METHOD_GET, 6.2//get请求
.url = url, 6.3
.event_handler = _http_fans_event_handle, 6.4//注册时间回调
.skip_cert_common_name_check = true, 6.5
};
esp_http_client_handle_t fans_client = esp_http_client_init(&config); 6.6 //初始化配置
esp_err_t err = esp_http_client_perform(fans_client);6.7 //执行请求
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Status = %d, content_length = %d", 6.8
esp_http_client_get_status_code(fans_client),//状态码
esp_http_client_get_content_length(fans_client));//数据长度
}
esp_http_client_cleanup(fans_client); 6.9//断开并释放资源
}
6.1.获取B站粉丝的URL,可以修改成自己的B站账号。
6.2.method用于配置http的运行方式,这里配置为获取请求,HTTP_METHOD_GET是HTTP method的枚举成员,里面包含更多的http运行方式详细见esp_http_client.h。
6.3..url配置http获取粉丝信息的URL(在WWW上,每一信息资源都有统一的且在网上的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位器),它是WWW的统一资源定位标志,就是指网络地址。)我们通过此网址获取当前系统的时间。
6.4.注册时间回调。函数原型如下:
static esp_err_t _http_fans_event_handle(esp_http_client_event_t *evt)
{
static char* output_buffer; // Buffer to store response of http request from event handler
static int output_len; // Stores number of bytes read
switch(evt->event_id) {
case HTTP_EVENT_ON_DATA: 6.4.1 //接收数据事件
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) {
if (output_buffer == NULL) {
output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
output_len = 0;
if (output_buffer == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
return ESP_FAIL;
}
}
memcpy(output_buffer + output_len, evt->data, evt->data_len); 6.4.2
printf("%.*s\n", output_len, output_buffer); 6.4.3
cjson_fans_info((char*)output_buffer); 6.4.4
output_len += evt->data_len;
}
break;
case HTTP_EVENT_ERROR:
ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADERS_SENT:
ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
if (output_buffer != NULL) {
// Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
// ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
free(output_buffer);
output_buffer = NULL;
}
output_len = 0;
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
int mbedtls_err = 0;
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
if (err != 0) {
ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
}
if (output_buffer != NULL) {
free(output_buffer);
output_buffer = NULL;
}
output_len = 0;
break;
}
return ESP_OK;
}
6.4.1如果http事件为接收数据事件,并且接收到的数据如果不为块和存储事件处理器响应请求的存储缓冲区为空的话,为它分配内存空间。
6.4.2将evt->data的数据拷贝到指向output_buffer缓冲区第output_len的位置。
6.4.3打印输出缓冲区存储的字节长度和内容。
6.4.4cjson解析获取到的粉丝信息。关于cjson的详细内容参考以下文章的内容:http://t.csdn.cn/aKnc8。此处只简单讲下ds_ui_fans_set_fans_num函数,g_fans_page是FANS_PAGE_T的结构体变量,两个函数都是设置粉丝数相关的结构体成员,函数原型如下:
/*
{ exmaple
"code":0,
"message":"0",
"ttl":1,
"data":{
"mid":383943678,
"following":13,
"whisper":0,
"black":0,
"follower":14233
}
}
*/
void cjson_fans_info(char *text)
{
cJSON *root,*psub,*ppsub;
int fans = 0;
//截取有效json
char *index=strchr(text,'{');
strcpy(text,index);
root = cJSON_Parse(text);
if(root!=NULL)
{
psub = cJSON_GetObjectItem(root, "data");
if(psub!=NULL && psub->type == cJSON_Object){
ppsub = cJSON_GetObjectItem(psub, "follower");
if(ppsub != NULL && ppsub->type == cJSON_Number){
fans = ppsub->valueint;
ESP_LOGI(TAG,"fans:%d",fans);
}
}
}
if(fans_type == 0){
ds_ui_fans_set_fans_num(fans);
fans_type = 1;
}else{
ds_ui_fans_set_aqifans_num(fans);
fans_type = 0;
}
cJSON_Delete(root);
}
void ds_ui_fans_set_fans_num(int fans){
g_fans_page.fans = fans;
}
void ds_ui_fans_set_aqifans_num(int fans){
g_fans_page.aqifans = fans;
}
typedef struct
{
int fans;
int aqifans;
uint8_t updateing;
uint8_t ten;
uint8_t utils;
}FANS_PAGE_T;
FANS_PAGE_T g_fans_page;
6.5.跳过服务器证书CN字段的任何验证。
6.6初始化http。这个函数必须作为第一个调用的函数,它返回一个esp_http_client_handle_t句柄作为其他函数接口的输入。当操作完成后,必须调用相应的esp_http_client_cleanup函数。
6.7在调用esp_http_client_handle_t函数和所有选项调用完成后,调用此函数执行请求。
6.8调用API函数获取状态码和数据长度打印到消息日志上。
6.9断开并释放资源,当操作完成后,必须调用相应的esp_http_client_cleanup函数。
7.获取城市信息。函数原型如下:
void http_city_get(){
//http client配置
esp_http_client_config_t config = {
.method = HTTP_METHOD_GET, 7.1 //get请求
.url = "http://pv.sohu.com/cityjson?ie=utf-8", 7.2 //请求url
.event_handler = _http_city_event_handle, 7.3 //注册时间回调
.skip_cert_common_name_check = true, 7.4
};
esp_http_client_handle_t city_client = esp_http_client_init(&config); 7.5 //初始化配置
esp_err_t err = esp_http_client_perform(city_client); 7.6 //执行请求
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Status = %d, content_length = %d", 7.7
esp_http_client_get_status_code(city_client),//状态码
esp_http_client_get_content_length(city_client));//数据长度
}
esp_http_client_cleanup(city_client); 7.8 //断开并释放资源
}
7.1.method用于配置http的运行方式,这里配置为获取请求,HTTP_METHOD_GET是HTTP method的枚举成员,里面包含更多的http运行方式详细见esp_http_client.h。
7.2.url配置http获取城市信息的URL(在WWW上,每一信息资源都有统一的且在网上的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位器),它是WWW的统一资源定位标志,就是指网络地址。)我们通过此网址获取当前系统的时间。
7.3注册时间回调。函数原型如下:
static esp_err_t _http_city_event_handle(esp_http_client_event_t *evt)
{
switch(evt->event_id) {
case HTTP_EVENT_ON_DATA: //接收数据事件
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) {
printf("%.*s\n", evt->data_len, (char*)evt->data);
cjson_city_info((char*)evt->data); 7.3.1
}
break;
case HTTP_EVENT_ERROR:
ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADERS_SENT:
ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
break;
}
return ESP_OK;
}
7.3.1cjson解析获取到的城市信息,并打印到消息日志上。关于cjson的详细内容参考以下文章的内容:http://t.csdn.cn/aKnc8。函数原型如下:
/* example
{
"cip":"121.32.92.51",
"cid":"440106",
"cname":"广东省广州市天河区"
}
*/
static void cjson_city_info(char *text)
{
cJSON *root,*psub;
char name[20];
char cid[20];
//截取有效json
char *index=strchr(text,'{');
strcpy(text,index);
root = cJSON_Parse(text);
if(root!=NULL)
{
psub = cJSON_GetObjectItem(root, "cname");
sprintf(name,"%s",psub->valuestring);
ESP_LOGI(TAG,"name:%s",name);
psub = cJSON_GetObjectItem(root, "cid");
sprintf(cid,"%s",psub->valuestring);
ESP_LOGI(TAG,"cid:%s",cid);
}
cJSON_Delete(root);
}
7.4跳过服务器证书CN字段的任何验证。
7.5初始化http。这个函数必须作为第一个调用的函数,它返回一个esp_http_client_handle_t句柄作为其他函数接口的输入。当操作完成后,必须调用相应的esp_http_client_cleanup函数。
7.6在调用esp_http_client_handle_t函数和所有选项调用完成后,调用此函数执行请求。
7.7调用API函数获取状态码和数据长度打印到消息日志上。
7.8断开并释放资源,当操作完成后,必须调用相应的esp_http_client_cleanup函数。