私の最終的な目標は、Wi-Fi を有効にするために ESP-01S を使用して Raspberry Pi Pico をセットアップすることです。Pico は定期的にサーバーにチェックインし、使用していないときは ESP をスリープ状態にします。2 つの間の通信は UART を介して行われます。ESP からの GET および POST HTTP リクエストの両方をサポートしたいと考えています。
これは、2 つのデバイス間で使用しているメッセージ構造です。
| 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 ファイルに直接貼り付けています。
メッセージを生成するために PC で使用しているコードのスニペットを次に示します。
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);
}
}
}
これは 2 つの問題のうちの 1 つですが、最初のインデックスをオフセットする元の char* の memcpy を実行することで回避策を見つけました。以下の最初の行は機能しますが、2 番目の行は LoadStoreAlignmentCause 例外をスローします。
理想的には、ここで何が起こっているのかを理解し、memcpy なしでこれを機能させたいと考えています。
ntohl(*(unsigned int *)(msg + 7)); // Works
int offset = 7;
ntohl(*(unsigned int *)(msg + offset)); // Throws Exception (9) LoadStoreAlignmentCause
私が経験している主な問題は、Python でサイズをパックしているときに、一部の 16 進数値が簡略化されていることです。例えばstruct.pack('!I', 54) == \x00\x00\x006
これが発生するntohl()
と、読み取ってはならないアドレスを読み取ったように見え、635 が出力されます。
この問題に関するいくつかの質問。この簡略化された 16 進構文の名前は何ですか? この短い手を出力しないようにPythonを取得する方法はありますか? または、これを ESP で機能させる方法について何か提案はありますか?