0

我的最终目标是设置一个带有 ESP-01S 的 Raspberry Pi Pico 来启用 wifi。Pico 将定期检查服务器并在不使用时让 ESP 进入睡眠状态。两者之间的通信是通过UART。我想同时支持来自 ESP 的 GET 和 POST HTTP 请求。

这是我在两个设备之间使用的消息结构。

 | Always start with MSG    | Request Type     | Next message Size
 |      | Next message size |                  |       | URL
 V      V                   V                  V       V
|-----|-------------------|-----|-------------------|-----------|
[M|S|G|\x00\|x00\|x00\|x03|G|E|T|\x00|\x00|\x00|\x1f|h|t|t|p|...]
[M|S|G|\x00\|x00\|x00\|x04|P|O|S|T|URL SIZE...|URL...|\x00|\x00|\x006|POST Data...]
|-----|-------------------|-------|-----------|------|---------------|------------|
                                                        ^              ^
                                                        |              | Post Data
                                                        | Post data size               

出于测试目的,我在 python 中生成字符串,打印它们并将它们直接粘贴到我正在闪烁到 ESP 的 .cpp 文件中。

这是我在我的电脑上用来生成消息的代码片段。

import struct
import json
url = "http://192.168.X.X:8090/korok"
size_of_url = struct.pack('!I', len(url))
data = json.dumps({
    "serial": "12345",
    "sensor_data": {"0": 75, "1": 67}
})
size_of_data = struct.pack('!I', len(data))
print(f"{struct.pack('!I', len('GET'))}GET{size_of_url}{url}")
print(f"{struct.pack('!I', len('POST'))}POST{size_of_url}{url}{size_of_data}{data}")

>>>> ...
b'\x00\x00\x00\x03'GETb'\x00\x00\x00\x1f'http://192.168.X.X:8090/korok
b'\x00\x00\x00\x03'GETb'\x00\x00\x00\x1f'http://192.168.X.X:8090/korokb'\x00\x00\x006'{"serial": "12345", "sensor_data": {"0": 75, "1": 67}}

这是在 ESP 上运行的代码。我对我正在经历的一些行为发表了评论。

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

#define GPIO_STATUS 2
#define BUFFER_SIZE 256
#define DATA_SIZE 4

char buf[BUFFER_SIZE];

void setup() {...}

...

// Struct is used so I can also get the size to use as an offset
// and read out part of the message in the buffer.
struct Message
{
  char *value;
  unsigned int size;
  unsigned int totalMessageSize;
};

Message readMessage(char *data)
{
  struct Message message;
  message.size = ntohl(*(unsigned int *)(data)); // Unable to read shorthand hex
  Serial.println(message.size);
  message.totalMessageSize = message.size + DATA_SIZE; // Shorthand is only 3 char
  message.value = (char *)malloc(message.size);
  Serial.println(message.size);
  int idx = DATA_SIZE;
  int jdx = 0;
  while (idx < message.size + DATA_SIZE && idx < BUFFER_SIZE)
  {
    message.value[jdx++] = data[idx++];
  }
  return message;
}

void loop()
{
  delay(3000);
  char * msg = "\x00\x00\x00\x03GET\x00\x00\x00\x1fhttp://192.168.X.X:8090/korok";
  // char *msg = read_message();
  if (msg)
  {
    Serial.print("\n");
    int bufferIdx = 0;

    struct Message request = readMessage(msg);
    bufferIdx = request.totalMessageSize;

    // This is odd and doing it due to odd behavior with ntohl and a variable
    // offset. See below.
    memcpy(msg, msg + bufferIdx, BUFFER_SIZE - bufferIdx);
    struct Message url = readMessage(msg);
    struct Message data;

    if (memcmp(request.value, "GET", 3) == 0)
    {
    }
    else if (memcmp(request.value, "POST", 4) == 0)
    {
      bufferIdx = url.totalMessageSize;
      memcpy(msg, msg + bufferIdx, BUFFER_SIZE - bufferIdx);
      struct Message data = readMessage(msg);
      Serial.println(data.value);
    }

    free(request.value);
    free(url.value);
    if (memcmp(request.value, "POST", 4) == 0)
    {
      free(data.value);
    }
  }
}

这是两个问题之一,尽管我通过对原始 char* 进行 memcpy 来偏移起始索引找到了一种解决方法。下面的第一行有效,但第二行引发 LoadStoreAlignmentCause 异常。

理想情况下,我想了解这里发生了什么,并在没有 memcpy 的情况下让它工作。

ntohl(*(unsigned int *)(msg + 7)); // Works

int offset = 7;
ntohl(*(unsigned int *)(msg + offset)); // Throws Exception (9) LoadStoreAlignmentCause

我遇到的主要问题是当我在 python 中打包大小时,一些十六进制值被简写。例如struct.pack('!I', 54) == \x00\x00\x006

当这种情况发生时ntohl(),它似乎读取了一个不应该读取的地址并输出 635。此外,由于我期望四个字符,消息的其余部分被一个索引关闭。

关于这个问题的几个问题。这种速记十六进制语法的名称是什么?反正有没有让python不输出这个速记?或者有什么关于如何让这个在 ESP 上工作的建议吗?

4

0 回答 0