Vrekrer / Vrekrer_scpi_parser

Simple SCPI parser for Arduino
MIT License
87 stars 26 forks source link

ESP32 / WiFi Hints #20

Closed Vanguard4893 closed 2 years ago

Vanguard4893 commented 2 years ago

I'm building an instrument based around the ESP32, and was wondering if I could get an example or hints on how to get this library operating correctly with the WiFi interface on that microcontroller?

I'm not much of a developer, and am rather stuck!

Cheers

Vrekrer commented 2 years ago

Hello

You might want to set up your instrument's WiFi connection as a socket server (SCPI instruments uses port 5025). Then read the messages sent to the socket into a *char variable and process that using the Execute function. Use a dummy Stream interface (like Serial) as the second parameter in the Execute call. (I will try to simplify this in a next release) If you have instrument output, write it back into the socket.

Ethernet_Instrument example does exactly that, but for the ENC28J60 Ethernet hardware.

On your controller/computer side, just connect to the socket and read/write it. Most VISA libraries does this for you if you use the 'TCPIP0::<your ip>::5025::SOCKET' string as the instrument identifier.

Vanguard4893 commented 2 years ago

I'm using WiFiServer (Identifier "SCPIClient") to open the port 5025, no problem, and can receive data on this port, and print back to it. I've put this together for processing the input, however the ESP32 crashes when called:

if(SCPIClient.connected()){
    char line_buffer[256];
  unsigned char read_length;
    read_length = SCPIClient.readBytesUntil('\n', line_buffer, 256);
    if(read_length > 0)
    {
      #ifdef SCPIDEBUG
      Serial.print("SCPI Message Buffer: ");
      Serial.println(line_buffer);
      #endif
      my_instrument.Execute(line_buffer, Serial); 
    }
}

Removing the my_instrumment.Execute line stops the crash, and the Serial debug prints out the proper *IDN? when sent, so I'm close to having it work by the look.

Cheers

Vrekrer commented 2 years ago

I have never used or tested WiFi hardware/libraries, but I believe that WiFiServer already creates a Stream interface. In that case, it is easier to use the ProcessInput(Stream &interface, const char* term_chars) function. All the examples uses that with Serial as Stream interface I think that your code will be my_instrument.ProcessInput(SCPIClient, "\n")

Take a look at this for an example using the Ethernet library that, as the web page says, should be very similar to the WiFi library.

Your code did not work because it has two problems:

Vanguard4893 commented 2 years ago

I should also point out, in my use case, sending the data in via the debug serial port with:

my_instrument.ProcessInput(Serial, "\n");

also results in the microcontroller crashing :

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x4000c547  PS      : 0x00060630  A0      : 0x800e8d25  A1      : 0x3ffb1d50  
A2      : 0x00000000  A3      : 0x0000003b  A4      : 0x3ffb81cc  A5      : 0x3ffb80c0  
A6      : 0x00000000  A7      : 0x00000000  A8      : 0x801090ec  A9      : 0x3ffb1d30  
A10     : 0x00000000  A11     : 0x3f41706c  A12     : 0x3ffb81cc  A13     : 0x00000001  
A14     : 0x3ffb89c9  A15     : 0x3ffb0060  SAR     : 0x0000000a  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  

ELF file SHA256: 0000000000000000

Backtrace: 0x4000c547:0x3ffb1d50 0x400e8d22:0x3ffb1d70 0x400e8fe6:0x3ffb1d90 0x400e910b:0x3ffb1e40 0x400d34de:0x3ffb1e60 0x400ed441:0x3ffb1fb0 0x4008a30e:0x3ffb1fd0

Rebooting...
Vanguard4893 commented 2 years ago

Hi Vrekrer, Thanks for your assistance so far.

I have tried the simple line:

my_instrument.ProcessInput(SCPIClient, "\n")

However I get the same crash & core dump:

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x4000c547  PS      : 0x00060e30  A0      : 0x800e8c81  A1      : 0x3ffb1e30  
A2      : 0x00000000  A3      : 0x0000003b  A4      : 0x3ffb8a5c  A5      : 0x3ffb80c0  
A6      : 0x00000000  A7      : 0x00000000  A8      : 0x801090b4  A9      : 0x3ffb1e10  
A10     : 0x00000000  A11     : 0x3f41704c  A12     : 0x3ffb8a5c  A13     : 0x00000001  
A14     : 0x00000005  A15     : 0x00000000  SAR     : 0x0000000a  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  

ELF file SHA256: 0000000000000000

Backtrace: 0x4000c547:0x3ffb1e30 0x400e8c7e:0x3ffb1e50 0x400e8fae:0x3ffb1e70 0x400e90d3:0x3ffb1f20 0x400d3512:0x3ffb1f40 0x400ed409:0x3ffb1fb0 0x4008a30e:0x3ffb1fd0

Rebooting...

I have also tried paring everything back to bare bones, with just a serial connection, and only an IDN command as per your example:


/*
Vrekrer_scpi_parser library.
SCPI Dimmer example.

Demonstrates the control of the brightness of a LED using SCPI commands.

Hardware required:
A LED attached to digital pin 9
or a resistor from pin 9 to pin 13 to use the built-in LED

Commands:
  *IDN?
    Gets the instrument's identification string

  SYSTem:LED:BRIGhtness <value>
    Sets the LED's brightness to <value>
    Valid values : 0 (OFF) to 10 (Full brightness)

  SYSTem:LED:BRIGhtness?
    Queries the current LED's brightness value

  SYSTem:LED:BRIGhtness:INCrease
    Increases the LED's brightness value by one

  SYSTem:LED:BRIGhtness:DECrease
    Decreases the LED's brightness value by one
*/

#include "Arduino.h"
#include "Vrekrer_scpi_parser.h"

SCPI_Parser my_instrument;

void Identify(SCPI_C commands, SCPI_P parameters, Stream& interface){
  interface.println(F("Vrekrer,Arduino SCPI Dimmer,#00,v0.4"));
}

void setup()
{
  my_instrument.RegisterCommand("*IDN?", &Identify);
  my_instrument.SetCommandTreeBase(F("SYSTem:LED"));

  Serial.begin(9600);
}

void loop(){
  my_instrument.ProcessInput(Serial, "\n");
}

This much simplified example also gives a core dump. Could this be something related to the ESP32 itself?

Vrekrer commented 2 years ago

Sorry. I never used an ESP32. I will try to get one and test it.

bogus43 commented 2 years ago

Hi @Vanguard4893 , I built and uploaded Your simplified sketch into ESP32 Dev Module and it works fine for me.

Vanguard4893 commented 2 years ago

Hi Bogus43,

How odd. I've read things on forums about ESP32 modules not all operating the same before, with the same code. Maybe I've got an odd one. Now I'm totally confused as to what's going on!

I'll try a full flash erase & give it another crack I think.

Cheers

Vanguard4893 commented 2 years ago

Seems that I just can't get it going on this particular ESP32 - I do have some other bare modules which are awaiting PCBs so I'll have to try with one of those.

I will report back if I get anywhere with it.

bogus43 commented 2 years ago

If you could share the code from the wifi (minimal code to reproduce the problem) then I can see if this would work on my ESP32. Maybe it's not a code problem, but a hardware.

Vanguard4893 commented 2 years ago

Hi Bogus43,

The code below should be a minimal implementation of what I'm doing. This compiles fine in Platformio. I get the same crash & core dump though. I have another ESP32 DevKit on order, so I'll try it on another one. I also think this is a hardware issue at this point.

#include <ESPAsyncWebServer.h>
#include <ESPAsyncWiFiManager.h>
#include <Vrekrer_scpi_parser.h>
AsyncWebServer server(80);
WiFiServer SCPI_Server(5025);
WiFiClient SCPIClient;
DNSServer dns;

SCPI_Parser my_instrument; //SCPI Object

bool fromSerial = true;
long oldTime = 0;

void PrintToInterface(char *print_str)
{
  SCPIClient.println(print_str);
}

/* SCPI FUNCTIONS */

void Identify(SCPI_C commands, SCPI_P parameters, Stream &interface)
{
  char IDN[] = "Instrument Identifier, v1.0";
  PrintToInterface(IDN);
}

void CheckForConnections()
{
  if (SCPI_Server.hasClient())
  {
    // If we are already connected to another computer,
    // then reject the new connection. Otherwise accept
    // the connection.
    if (SCPIClient.connected())
    {
      Serial.println(F("SCPI Connection rejected"));
      SCPIClient.stop();
    }
    else
    {
      Serial.println(F("SCPI Connection accepted"));
      SCPIClient = SCPI_Server.available();
    }
  }
}

void setup(void)
{

  Serial.begin(9600); //Init Serial Link
  while (!Serial)
    ;

  my_instrument.RegisterCommand("*IDN?", &Identify);

  AsyncWiFiManager wifiManager(&server, &dns);
  wifiManager.autoConnect("ESP32");
  wifiManager.setConfigPortalTimeout(180);
  SCPI_Server.begin(); //Begin SCPI Server
}

void loop(void)
{

  if (millis() - oldTime > 500)
  {
    CheckForConnections();
  }

  fromSerial = true;
  my_instrument.ProcessInput(Serial, "\n");

  if (SCPIClient.connected())
  {
    fromSerial = false;
    my_instrument.ProcessInput(SCPIClient, "\n");
  }
}
Vanguard4893 commented 2 years ago

Hi guys,

I've now tried the same code on 3 different ESP32 microcontrollers (two devkits & a bare module), and I get the exact same CPU crash & reboot on all of them. Definitely lost as to what to do now!

Cheers

bogus43 commented 2 years ago

Maybe try upload code from Arduino IDE and check that You selected proper board version. I changed 1 library [ESPAsyncWiFiManager], see link: https://www.arduino.cc/reference/en/libraries/espasync_wifimanager/

Vanguard4893 commented 2 years ago

Hi Bogus43,

I've tried in the Arduino IDE, and while the code compiles, I get the same crash when I feed the micro an *IDN? command over network.

My board settings all appear to be correct, however I'm open to any suggestions. (ESP32 Dev Module, 240MHz Core Clock, DIO, 80MHz, SPI Flash)

Cheers

Vrekrer commented 2 years ago

Hello.

I created this example WiFi_ESP32.ino that works on Serial and WiFi.

My setup is:

Hardware:

Software:

Vanguard4893 commented 2 years ago

Hi Vrekrer,

Thanks for the example code. I've cracked the problem! I still couldn't get it to work, then realised I wasn't using the git version of the library - the one that's in the Arduino library manager & Platformio's library manager is an older version, and causes the crash. With the library manager version replaced with a clone from git, all works correctly.

Thanks!

Vrekrer commented 2 years ago

Thanks for the feedback.

As soon as I get some time, I will make a new release.

Some remarks about using this library in an ESP32 (or any other system with "a lot" of RAM)

Vanguard4893 commented 2 years ago

Hi Vrekrer,

Thanks for the hints with the defines, I did indeed have to make some edits to prevent hash collisions in my command tree.

I do believe this is solved now, so I'll close off this issue. Using the git version of the library fixed all the issues I have encountered.

Cheers