20201106 MicroPython文件传输协议

能够通过MicroPython访问ArduSensorPlatform的Host

execute_from_str可以正常执行

然后尝试写一个Scripter能够接受Python代码写入MicroPython内置文件并执行。访问文件系统应该是和uos module有关,正在看uos的源码。

发现webrepl应该是支持文件读写的

typedef struct _mp_obj_webrepl_t {
    mp_obj_base_t base;
    mp_obj_t sock;
    byte state;
    byte hdr_to_recv;
    uint32_t data_to_recv;
    struct webrepl_file hdr;
    mp_obj_t cur_file;
} mp_obj_webrepl_t;

但是c语言写的通信协议我还没看明白,所以我先开始看前端的js代码。

连接webrepl需要esp32和主机连接到同一个wifi,两者通过websocket字节流进行通信。

host端需要获取esp32设置的ip地址,通过8266端口与esp32通过websocket相连接。

具体Host端的通信协议如下:

提取文件

  1. 首先发送第一个报文,指明文件信息,创建Byte Buffer长度为2+1+1+8+4+2+64=74的Uint8数组rec,开头WA,第2个元素为2,之后13个元素为0。

之后16和17这2个元素存储文件名长度

rec[16] = src_fname.length & 0xff; rec[17] = (src_fname.length >> 8) & 0xff;

其余用于存储文件名

for (var i = 0; i < 64; ++i) {
  if (i < src_fname.length) {
      rec[18 + i] = src_fname.charCodeAt(i);
  } else {
      rec[18 + i] = 0;
  }
}

然后发送rec

avatar

  1. 解析响应报文,以WB开头且后2位为0则继续。新建一个长度为1的Byte Array,第0个元素为0然后发送。

avatar

avatar

  1. 解析之后的响应报文,由于esp32端会将文件分批发送,所以需要分几次接受最后把数据聚合到一起。报文开头2位为接受数据大小。

avatar

var sz = data[0] || (data[1] << 8);

然后校验数据长度是否正确即接受的字节流长度是否为sz + 2

如果是则继续接收。一批数据接受完毕后要在后两位把本次接受的数据的长度记录下来。

var new_buf = new Uint8Array(get_file_data.length + sz);
new_buf.set(get_file_data);
new_buf.set(data.slice(2), get_file_data.length);

每次接收完毕要新建一个长度为1的Byte Array,第0个元素为0并发送。

avatar

  1. 如果接收到的数据长度为0,则表明数据接收完毕。将数据转换为application/octet-stream类型的Blob并存储到本地。

avatar

update_file_status('Got ' + get_file_name + ', ' + get_file_data.length + ' bytes');
saveAs(new Blob([get_file_data], {type: "application/octet-stream"}), get_file_name);

发送文件

  1. 首先是发送第一个报文,指明文件信息,创建一个Uint8数组rec即Byte Buffer,长度为2+1+1+8+4+2+64=74。开头为W和A,第2个元素为数字1(0x1),之后连续9个都为0x0。接下来的12、13、14、15这4个元素存储文件大小,
rec[12] = dest_fsize & 0xff; rec[13] = (dest_fsize >> 8) & 0xff; rec[14] = (dest_fsize >> 16) & 0xff; rec[15] = (dest_fsize >> 24) & 0xff;

再之后16和17这2个元素存储文件名长度

rec[16] = dest_fname.length & 0xff; rec[17] = (dest_fname.length >> 8) & 0xff;

剩余64位用于存储文件名。

然后发送rec。

  1. 解析发送上面的报文之后接受到的响应报文,如果以WB开头且第2和第3位为0(data[2] | (data[3] << 8) == 0)则继续。将需要发送的文件转换成byte数组分片发送,片长度为1024byte。
for (var offset = 0; offset < put_file_data.length; offset += 1024) {
  ws.send(put_file_data.slice(offset, offset + 1024));
}
  1. 最后解析收到的第二个报文,WB开头且后2位为0表示发送成功,否则失败。

本文章使用limfx的vscode插件快速发布