Populating an array using pointers

Hi everyone, hope you're having a good day.

I am trying to send ADC data over TCP. For speed, I want to read ADC data and fill it to a buffer array (called addr) and only when full, send over as a single packet.

May be clearer to see this diagram of array structure:

My pseudo-code:

Read ADC data as it comes in and start to populate array "addr" (currently using adcData as random data):
- Read channel 0 to channel 8 one at a time and add to "addr"
- Then move to next timestep and read channels again
- After 64 timesteps send data as packet over TCP using ESP32

Here is my code:

#include <WiFi.h>

/* WiFi network name and password */
const char * ssid = "WiFi Guest_";
const char * pwd = "";

/* Ip address of server (PC) and udp port - same as python script */
const char * hostIP = "172.24.5.52";
const int port = 1234;

//Test buffer
uint8_t adcData[4] = {0b11011010,0b11100010,0b00111010,0b01011010}; // Decimal: 218, 226, 58, 90

// 64 timesteps, hence 64 long (4 bytes) of memory designated to each channel per buffer cycle
long* addr;

int timestep = 0;
int channel = 0;

void setup()
{
    Serial.begin(115200);
    Serial.print("Connecting to ");
    Serial.println(ssid);
    /* connect to your WiFi */
    WiFi.begin(ssid, pwd);
    /* wait until ESP32 connect to WiFi*/
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi connected with IP address: ");
    Serial.println(WiFi.localIP());

    // allocate new memory: 64 timesteps, 8 channels each, storing longs (4 bytes)
    addr = (long*) malloc(512);
}


void loop()
{
    if(timestep == 0 && channel == 0)
    {
      // Flag to other core that packet is ready

      
      // Send packet data
      WiFiClient client;
    
      if (!client.connect(hostIP, port)) {
          Serial.println("connection failed");
          return;
      }
      /* This will send the data to the server */
      client.write(*addr);
      Serial.print("Sent data");
      client.stop();

      for(int i = 0; i<sizeof(addr); i++){
          Serial.print(addr[i]);
          Serial.print(", ");
        }

      // Reallocate address memory 
      addr = (long*) realloc(addr, 512);
    }

    // read ADC and proccess it (checksum etc.)
    
    // write adcData to array in addr to be stored as buffer
    *(addr+(channel + (timestep*8))) =  

    // after 64 timesteps, timesteps will be reset to zero
    timestep = (timestep + 1) % 64;
    // after 8 channels, channels will be reset to zero
    channel = (channel + 1) % 8;
    
}

It compiles but I do not receive any data through to server. Don't think array is populated, but giving me gibberish when printing to Serial.

I would expect this to send four bytes:

 client.write(*addr);

Because *addr is a single long. You need to tell write how much data to send and probably cast addr to char*.

What is the purpose of doing this?

  • should client be global? otherwise you need to re-connect each iteration of loop()
  • why client.stop()?
  • may want to have states indicating what to do in loop() such at connecting to wifi or normal processing
  • don't understand timestep, after 64 iterations of loop(). how often is that if you don't have to re-connect to WiFi?
  • why not use millis() to make a measurement at a precise time (e.g. 100 msec)
  • each measure inserts adds data to adcData using an index to keep track of the next empty location
  • after adding 4, incrementing the index, send the packet and reset the index to zero

Why not create a global buffer of the right size rather than dynamic allocation ?

So... each 'timestep' you are taking a 1-byte sample from one of 8 ADC channels and after 64 timesteps (8 samples from each of 8 channels) you send all 64 bytes. 'addr' is a strange name for a buffer of analog input values.

uint8_t buffer[8][8];
int channel = 0;
int sample = 0;


void loop()
{
   buffer[sample][channel] = analogGet(channel);
   channel = (channel + 1) % 8;
   if (channel == 0)
  {
     sample = (sample + 1) % 8;
     if (sample == 0)
        client.write((char *)buffer, sizeof buffer);
  }
}

Thank you all for your comments - very helpful.

I think I will use a global buffer rather than dynamic allocation, to make it easier.
I have moved the instantiation of WiFiClient client to the top.

I believe I have to use client.stop() after sending each packet otherwise it will print empty values when buffer is filling up and nothing is being told to print. Is there a more efficient way?

WiFiClient client;

void loop()
{ 
   buffer[timestep][channel] = analogRead(16);
   channel = (channel + 1) % 8;
 
    if (channel == 0)
    { 
       timestep = (timestep + 1) % 8;
       if (timestep == 0)
       {
          if (!client.connect(hostIP, port)) {
          Serial.println("connection failed");
          return;
          }
          client.write((char *)buffer, sizeof(buffer));
          client.stop();
        }
      
    }
}

Thanks John this is a very neat solution.

don't see how stop() prevents printing.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.