0

My end goal is to set up a Raspberry Pi Pico with an ESP-01S to enable wifi. The Pico will periodically check in with the server and put the ESP to sleep when not in use. Communication between the two is over UART. I want to support both a GET and POST HTTP request from the ESP.

This is the message structure I am using between the two devices.

 | 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               

For testing purposes I am generating the strings in python, printing them and pasting them directly in the .cpp file I'm flashing onto the ESP.

Here is the snippet of code I'm using on my pc to generate the message.

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}}

And here is the code running on the ESP. I left comments on some of the behaviors I'm experiencing.

#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);
    }
  }
}

Here is one of the two issues, though I found a workaround by doing a memcpy of my original char* offsetting the beginning index. The first line below works but the second throws LoadStoreAlignmentCause exception.

Ideally I'd like to understand what's going on here and to get this working without the memcpy.

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

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

The main issue I'm experiencing is when I'm packing the size in python some hex values are being shorthanded. e.g struct.pack('!I', 54) == \x00\x00\x006

When this happens ntohl() seems to read an address it shouldn't and outputs 635. Also since I'm expecting four char the rest of the message is off by one index.

A few questions regarding this issue. What is the name of this shorthand hex syntax? Is there anyway to get python to not output this short hand? Or are there any suggestions on how to get this working on the ESP?

Sean O'Rourke
  • 182
  • 1
  • 2
  • 11
  • what is the reason for dynamic allocations? why do you use memcpy for strings? do you terminate the strings? – Juraj Jun 18 '21 at 18:59
  • > What is the reason for dynamic allocations? No real reason, I don't often work in C, what would be optimal here? > Why do you use memcpy for strings? I don't want to, when I try to use ntohl and pass in `nthol(*(unsigned int *)data + offset)` I get an exception. See the section in the post about it. Not sure why that's happening. > Do you terminate the strings? No, but gives me some ideas. – Sean O'Rourke Jun 18 '21 at 20:40
  • That's an odd mix of ASCII and binary data. The message format does not seem reliable; i.e. there's no CRC or checksum to validate the message is received correctly – sawdust Jun 18 '21 at 23:01
  • It would be much easier to just send a serialised json. – hcheung Jun 20 '21 at 01:18
  • Gave this another shot with no luck. Code that was working is no longer working. Trying with a simple message. `char * msg = "\x00\x00\x00\x05\x53\x4c\x45\x45\x50";` Works in this line `unsigned int test = ntohl(*(unsigned int *)(msg));` But as soon as I move it into its own function the same line of code throws an exception. `LoadStoreAlignmentCause: Load or store to an unaligned address` ` void readMessage(char *msg) { unsigned int test = ntohl(*(unsigned int *)(msg)); } readMessage(msg); ` – Sean O'Rourke Jun 21 '21 at 18:04

0 Answers0