http_server.c 14.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include "esp_netif.h"
#include <esp_wifi.h>
#include <esp_system.h>
#include "nvs_flash.h"
#include "esp_ota_ops.h"
#include "http_server.h"
#include "Protocol_User.h"

static const char *TAG = "http_server";

char buf[MAX_OTA_BUFF]; // 接收服务端传来的文件缓存, 必须使用全局变量, 否则会触发看门狗复位, 原理未知
extern void Cache_data(unsigned char* p,uint32_t len);
extern void SetUpgradeFlashSize(uint32_t size,uint32_t len);
extern void SetUpgradeStart(void);//初始状态
static unsigned char softap_ota_start = 0;

httpd_handle_t http_server = NULL;

static esp_err_t index_html_get_handler(httpd_req_t *req)
{
    ESP_LOGI(TAG, "---- 回到起始页");
    httpd_resp_set_status(req, "307 Temporary Redirect");
    httpd_resp_set_hdr(req, "Location", "/");
    httpd_resp_send(req, NULL, 0);
    return ESP_OK;
}

static esp_err_t favicon_get_handler(httpd_req_t *req)
{
    extern const unsigned char favicon_ico_start[] asm("_binary_favicon_ico_start");
    extern const unsigned char favicon_ico_end[] asm("_binary_favicon_ico_end");
    const size_t favicon_ico_size = (favicon_ico_end - favicon_ico_start);
    ESP_LOGI(TAG, "---- 下载网站图标");
    httpd_resp_set_type(req, "image/x-icon");
    httpd_resp_send(req, (const char *)favicon_ico_start, favicon_ico_size);
    return ESP_OK;
}

static esp_err_t http_resp_dir_html(httpd_req_t *req)
{
    extern const unsigned char ota_page_start[] asm("_binary_ota_page_html_start");
    extern const unsigned char ota_page_end[] asm("_binary_ota_page_html_end");
    const size_t ota_page_size = (ota_page_end - ota_page_start);

    ESP_LOGI(TAG, "---- 下载网站起始页");
    httpd_resp_set_type(req, "text/HTML");
    httpd_resp_send(req, (const char *)ota_page_start, ota_page_size);
    return ESP_OK;
}

static esp_err_t download_get_handler(httpd_req_t *req)
{
    const char *uri_get = req->uri;
    ESP_LOGI(TAG, "---- GET URI: 192.168.4.1%s", req->uri);
    if (strcmp(uri_get, "/") == 0)
    {
        return http_resp_dir_html(req);
    }
    else if (strcmp(uri_get, "/favicon.ico") == 0)
    {
        return favicon_get_handler(req);
    }
    else
    {
        ESP_LOGI(TAG, "---- 非预设GET, 不处理, 直接回到起始页");
        return index_html_get_handler(req);
    }

    return ESP_OK;
}

static esp_err_t app_post_handler(httpd_req_t *req)
{
    int ret = 0;
    int recv_block = 0;
    int remaining = req->content_len;
    int total = remaining;
    double percent = 0.0;

    ESP_LOGI(TAG, "---- 应用程序更新, 需接收数据长度(bytes): %d", remaining);
    esp_ota_handle_t app_update_handle = 0;
    const esp_partition_t *app_update_partition = esp_ota_get_next_update_partition(NULL);
    esp_err_t err = esp_ota_begin(app_update_partition, OTA_WITH_SEQUENTIAL_WRITES, &app_update_handle);
    while (remaining > 0)
    {
        /* Read the data for the request */
        if ((ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)))) <= 0)
        {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT)
            {
                /* Retry receiving if timeout occurred */
                continue;
            }
            return ESP_FAIL;
        }

        err = esp_ota_write(app_update_handle, buf, ret);
        if (err != ESP_OK)
        {
            ESP_LOGI(TAG, "---- 写入数据失败, 错误信息:%s", esp_err_to_name(err));
        }
        else
        {
            remaining -= ret;
            recv_block++;
            if ((recv_block % 20) == 0)
            {
                percent = 100.0 - (double)(remaining * 100) / (double)total;
                ESP_LOGI(TAG, "---- 写入OTA升级数据: %.2f%%", percent);
            }
        }

        // 增加20ms延时, 解决CPU0看门狗超时的问题
        vTaskDelay(pdMS_TO_TICKS(20));
    }
    err = esp_ota_end(app_update_handle);
    if (err == ESP_OK)
    {
        esp_err_t err = esp_ota_set_boot_partition(app_update_partition);
        if (err != ESP_OK)
        {
            ESP_LOGI(TAG, "---- 设备启动分区失败, 错误信息:%s", esp_err_to_name(err));
        }
        else
        {
            ESP_LOGI(TAG, "---- 应用程序更新完成, 3秒后自动重启.");
            httpd_resp_send_chunk(req, NULL, 0);
            // delele_tasks();
            // httpd_resp_sendstr(req, "<p>应用程序更新完成,3秒后自动重启.</p>");
            vTaskDelay(pdMS_TO_TICKS(3000));
            //esp_restart();
            SendCmd_ResetComond();

        }
    }

    // End response
    // httpd_resp_sendstr(req, "<p>数据上传完成,但应用更新不成功,请重试.</p>");
    ESP_LOGI(TAG, "---- 数据接收完成, OTA失败, 1秒后自动重启.");
    httpd_resp_send_chunk(req, NULL, 0);
    // delele_tasks();
    vTaskDelay(pdMS_TO_TICKS(1000));
    esp_restart();
    return ESP_OK;
}

// static esp_err_t assert_post_handler(httpd_req_t *req)
// {
//     int ret, remaining = req->content_len;

//     while (remaining > 0)
//     {
//         /* Read the data for the request */
//         if ((ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)))) <= 0)
//         {
//             if (ret == HTTPD_SOCK_ERR_TIMEOUT)
//             {
//                 /* Retry receiving if timeout occurred */
//                 continue;
//             }
//             return ESP_FAIL;
//         }

//         remaining -= ret;

//         // ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
//         // 数据处理代码
//         // ESP_LOGI(TAG, "====================================");
//     }

//     // End response
//     httpd_resp_send_chunk(req, NULL, 0);
//     return ESP_OK;
// }

// static esp_err_t storage_post_handler(httpd_req_t *req)
// {
//     int ret, remaining = req->content_len;

//     while (remaining > 0)
//     {
//         /* Read the data for the request */
//         if ((ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)))) <= 0)
//         {
//             if (ret == HTTPD_SOCK_ERR_TIMEOUT)
//             {
//                 /* Retry receiving if timeout occurred */
//                 continue;
//             }
//             return ESP_FAIL;
//         }

//         remaining -= ret;

//         // ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
//         // 数据处理代码
//         // ESP_LOGI(TAG, "====================================");
//     }

//     // End response
//     httpd_resp_send_chunk(req, NULL, 0);
//     return ESP_OK;
// }
static void MSI_Print_mem16(size_t len,char *buf)
{
    for (size_t i = 0; i < len; )
    {
        ESP_LOGI("MSI","%02xh:  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",i,\
        buf[i+0],buf[i+1],buf[i+2],buf[i+3],buf[i+4],buf[i+5],buf[i+6],buf[i+7],
        buf[i+8],buf[i+9],buf[i+10],buf[i+11],buf[i+12],buf[i+13],buf[i+14],buf[i+15]);
        i+=16;
    }
} 
/*上传文件名是BAT32A239dat.bin的处理函数*/
static esp_err_t nation_post_handler(httpd_req_t *req)
{
  
    int recv_block = 0;
    double percent = 0.0;
    int ret, remaining = req->content_len;
    int total = remaining;
    int err_timeout_retry_cnt = 0;

    size_t erase_size = 0;
    size_t erase_offset = 0;
    size_t write_offset = 0;

    int Addr = 0;

    esp_err_t err = ESP_OK;
    const char *partition_label = "assert";
    const esp_partition_t *assert_update_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, partition_label);

      // if (Sys_Run_hdl != NULL)
    // {
    //     vTaskDelete(Sys_Run_hdl);
    //     Sys_Run_hdl = NULL;
    //     vTaskDelay(pdMS_TO_TICKS(100));
    // }

    //SetUpgradeFlashSize(remaining); // 设定文件大小
    
    ESP_LOGI(TAG, "---- 国民技术程序文件: 需要接收的数据(byte) = %d", remaining);
    while (remaining > 0)
    {
        /* Read the data for the request */
        if ((ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)))) <= 0)
        {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT)
            {
                err_timeout_retry_cnt++;
                if (err_timeout_retry_cnt >= MAX_RETRY_COUNT)
                {
                    httpd_resp_send_408(req);
                    httpd_resp_send_chunk(req, NULL, 0);
                    ESP_LOGE(TAG, "---- 接收数据超时, 退出升级流程, 请保持无线连接稳定后再试.");
                    return ESP_FAIL;
                }
                /* else
                {
                    Retry receiving if timeout occurred 
                    
                            continue;
                }*/
            }
            else
            {
                ESP_LOGI("MSI","total : %d  \n",total);
                ESP_LOGI("MSI","remaining : %d  \n",remaining);
                
               err_timeout_retry_cnt = 0; 
            }
        }
        if(total == remaining)//下载长度+地址
        {
            Addr = 0;
            Addr |= buf[8];
            Addr <<= 8;
            Addr |= buf[9];
            Addr <<= 8;
            Addr |= buf[10];
            Addr <<= 8;
            Addr |= buf[11];
            SetUpgradeFlashSize(remaining, Addr);
        }
        while (erase_offset < write_offset + ret)
        {
            err = esp_partition_erase_range(assert_update_partition, erase_offset, assert_update_partition->erase_size);
            if (err == ESP_OK)
            {
                erase_offset += assert_update_partition->erase_size;
            }
            else
            {
                httpd_resp_send_chunk(req, NULL, 0);
                //ESP_LOGE(TAG, "---- assert 分区擦除失败(%s), 分区容量 = 0x%x, 偏移地址 = 0x%x, 擦除长度 = 0x%x", esp_err_to_name(err), assert_update_partition->size, erase_offset, assert_update_partition->erase_size);
                return ESP_FAIL;
            }
        }

        err = esp_partition_write(assert_update_partition, write_offset, buf, ret);
        if (err == ESP_OK)
        {
            remaining -= ret;
            write_offset += ret;
            recv_block++;
            if ((recv_block % 32) == 0)
            {
                percent = 100.0 - (double)(remaining * 100) / (double)total;
                ESP_LOGI(TAG, "---- 写入数据(%.2f%%), recv_block = %d", percent, recv_block);
            }
        }
        else
        {
            httpd_resp_send_chunk(req, NULL, 0);
            ESP_LOGE(TAG, "---- assert 分区写数据失败(%s)", esp_err_to_name(err));
            return ESP_FAIL;
        }

        // 增加20ms延时, 解决CPU0看门狗超时的问题
        vTaskDelay(pdMS_TO_TICKS(20));

    }
    ESP_LOGI(TAG, "---- write_offset = %d", write_offset);
    if (write_offset == total)
    {
        ESP_LOGI(TAG, "---- assert 分区更新完成, 1秒后自动重启.");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
    else
    {
        httpd_resp_send_chunk(req, NULL, 0);
        ESP_LOGE(TAG, "---- assert 分区更新数据部分丢失");
        return ESP_FAIL;
    }
    SetUpgradeStart(); // 启动升级
    ESP_LOGI(TAG, "---- 国民技术程序文件: 接收完成");
    return ESP_OK;
    
}


void Nat32G031_ReqReset(void)
{
    ESP_LOGI(TAG, "---- NAT32G031程序更新完成, 3秒后自动重启.");
    // delele_tasks();
    // httpd_resp_sendstr(req, "<p>应用程序更新完成,3秒后自动重启.</p>");
    vTaskDelay(pdMS_TO_TICKS(3000));
    esp_restart();
}

static esp_err_t upload_post_handler(httpd_req_t *req)
{
    const char *uri_post = req->uri;
    ESP_LOGI(TAG, "---- POST URI: 192.168.4.1%s", req->uri);
    if (strcmp(uri_post, "/upload/RT200T-2.bin") == 0)
    {
        return app_post_handler(req);
    }
    // else if (strcmp(uri_post, "/upload/mmap_assert.bin") == 0)
    // {
    //     return assert_post_handler(req);
    // }
    // else if (strcmp(uri_post, "/upload/storage.bin") == 0)
    //{
    //    return storage_post_handler(req);
    //}
    else if (strcmp(uri_post, "/upload/BAT32G139.bin") == 0)
    {
        return nation_post_handler(req);
    }
    else
    {
        ESP_LOGI(TAG, "---- 非预设POST, 不处理, 直接回到起始页");
        return index_html_get_handler(req);
    }

    return ESP_OK;
}

void set_softap_ota_status(unsigned char status)
{
    softap_ota_start = status;
}

unsigned char get_softap_ota_status(void)
{
    return softap_ota_start;
}

httpd_handle_t start_webserver(void)
{
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.lru_purge_enable = true;
    config.uri_match_fn = httpd_uri_match_wildcard;

    // Start the httpd server
    ESP_LOGI(TAG, "---- 服务器端口号: '%d'", config.server_port);
    if (httpd_start(&server, &config) == ESP_OK)
    {
        // Set URI handlers
        ESP_LOGI(TAG, "---- 注册URI管理程序");

        // 注册客户端下载行为
        httpd_uri_t download_cfg = {
            .uri = "/*",
            .method = HTTP_GET,
            .handler = download_get_handler,
            .user_ctx = NULL};
        httpd_register_uri_handler(server, &download_cfg);

        // 注册客户端上传行为
        httpd_uri_t upload_cfg = {
            .uri = "/upload/*",
            .method = HTTP_POST,
            .handler = upload_post_handler,
            .user_ctx = NULL};
        httpd_register_uri_handler(server, &upload_cfg);

        return server;
    }

    ESP_LOGI(TAG, "---- 服务器启动时发生错误.");
    return NULL;
}

esp_err_t stop_webserver(httpd_handle_t server)
{
    return httpd_stop(server);
}

/******************************************
 *根据某种状态自动开关webserver的监听处理,
 *没有任何STA连接AP,自动关闭webserver,
 *任意STA连接AP,自动开启webserver.
 ******************************************/
void connect_handler(void *arg)
{
    httpd_handle_t *server = (httpd_handle_t *)arg;
    if (*server == NULL)
    {
        ESP_LOGI(TAG, "---- 开启HTTP服务器");
        *server = start_webserver();
    }
}

void disconnect_handler(void *arg)
{
    httpd_handle_t *server = (httpd_handle_t *)arg;
    if (*server)
    {
        ESP_LOGI(TAG, "---- 关闭HTTP服务器");
        if (stop_webserver(*server) == ESP_OK)
        {
            *server = NULL;
        }
        else
        {
            ESP_LOGE(TAG, "Failed to stop http server");
        }
    }
}

httpd_handle_t http_service(void)
{
    static httpd_handle_t server = NULL;

    // 首次启动http_server
    server = start_webserver();
    if (server)
    {
        ESP_LOGI(TAG, "---- HTTP服务器开启成功.");
    }
    else
    {
        ESP_LOGI(TAG, "---- HTTP服务器开启失败.");
    }

    return server;
}