简体   繁体   中英

Sending image from node.js server to ESP32 using ESP-IDF

I'm trying to send an image from a node.js server to ESP32 chip using WIFI and ESP-IDF. I believe this transfer happens over a TCP/IP connection. I'm able to send a regular text data using a http get request or the http_perform_as_stream_reader function shown below. But when it comes to transferring an image from the node.js server, I'm unable to do so. I seem to be receiving garbage on the client side. The ultimate goal is to save the image into a spiffs file on ESP32. Here's my code:

Server side:

const {imageprocess, convertToBase64} = require('../canvas');
const fs = require('fs');
const express = require('express');
const router = express.Router();
const path = require('path');

const imageFile = path.resolve(__dirname, "../images/file31.png")

router.get('/', funcAllStream)

module.exports = router;


function funcAllStream(req, res, next){
        newStream(res, imageFile)
}

function newStream(res, imageFile){
  var readStream = fs.createReadStream(imageFile);
  readStream.on('data', chunk => {
    res.send(chunk.toString('hex'));
  })
}

Client side (C++):

static void http_perform_as_stream_reader(void)
{
    char *buffer = malloc(MAX_HTTP_RECV_BUFFER + 1);
    esp_http_client_config_t config = {
        .url = "http://192.168.1.155:8085/api?file=image1.png"
    };
    esp_http_client_handle_t client = esp_http_client_init(&config); //calls esp_http_client_init from standard ESP32 component esp_http_client
    esp_err_t err;
    if ((err = esp_http_client_open(client, 0)) != ESP_OK) {
        return;
    }
    int content_length =  esp_http_client_fetch_headers(client); //calls esp_http_client_fetch_headers from standard ESP32 component esp_http_client
    int total_read_len = 0, read_len;
    if (total_read_len < content_length && content_length <= MAX_HTTP_RECV_BUFFER) {//MAX_HTTP_RECV_BUFFER defined to be larger than image1.png file on server side
        read_len = esp_http_client_read(client, buffer, content_length); //calls esp_http_client_read from standard ESP32 component esp_http_client
        if (read_len <= 0) {
            ESP_LOGE(TAG, "Error read data");
        }
        buffer[read_len] = 0;
    }
    esp_http_client_close(client);
    esp_http_client_cleanup(client);
    free(buffer);
}

http_perform_as_stream_reader();

On the client side, I've made sure buffer has been allocated more space than the image file size. When I print out what's been stored in buffer on the client side, I see absolute garbage. Server side sends buffer stream that looks like this:

<Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 64 00 00 00 64 08 06 00 00 00 70 e2 95 54 00 00 00 06 62 4b 47 44 00 ff 00 ff 00 ff a0 bd a7 ...>

This is what the client buffer looks like before receiving data:

���?Lv�~sN\
L��8J��s-�z���a�{�;�����\���~�Y���Di�2���]��|^,�x��N�݁�����`2g����n�w��b�Y�^���a���&��wtD�>n@�PQT�(�.z��(9,�?İ�

This is what client buffer looks like after receiving data:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/octet-stream
Content-Length: 4517
ETag: W/"11a5-IhqwFPYLgC+NRfikTwS2exLtCWQ"
Date: Mon, 19 Apr 2021 16:15:48 GMT
Connection: keep-alive

�PNG

So how do I ensure that the client side buffer actually receives correct data in the correct format from the server side? Ultimately, I want to store the data in a spiffs file on the client side and open the file to display the image transmitted from the node.js server.

Update: After converting data to hex format on the server side, I can confirm that the client receives the correct hex string. This is what I see on both the server and client side:

89504e470d0a1a0a0000000d4948445200000064000000 ... 0fcc3c0ff03b8c85cc0643044ae0000000049454e44ae426082

Starting and ending signatures are consistent with that of a png file.

I've set the client side buffer at 10000 (content length is 9037 bytes). Still, I receive the hex string in two chunks. In my client side code, function http_perform_as_stream_reader calls esp_http_client_fetch_headers from the ESP component esp_http_client , which in turn calls the lwip_rec_tcp function from lwip/src/api/sockets.c . Since I've set the buffer capacity to 10000 (a rather large amount), esp_http_client_fetch_headers fetches a rather large chunk of the hex string along with the headers. Then when the http_perform_as_stream_reader function calls the esp_http_client_read function, it again calls lwip_rec_tcp which now runs a do... while loop until it retrieves the remaining server side data. Since lwip_rec_tcp stores all the data in the buffer, which has low storage capacity (certainly not up to the 10000 that I set for it in the code), the first chunk gets overwritten by the final chunk of data. So how do I ensure that the client->response->buffer pointer captures all the chunks of data without modifying lwip_rec_tcp to include uploading data to the spiffs file inside the do... while loop?

Application should not assume that esp_http_client_read reads same number of bytes specified in the length argument. Instead, application should check the return value of this API which indicates number of bytes read by corresponding call. If the return value is zero, it indicates that complete data is read.

To work correctly, application should call esp_http_client_read in a while loop with a check for return value of esp_http_client_read.

You can also use esp_http_client_read_response , which is a helper API for esp_http_client_read to internally handle the while loop and read complete data in one go.

Please refer http_native_request example which uses esp_http_client_read_response() API.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM