Vrekrer / Vrekrer_scpi_parser

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

SCPI dimmer error #6

Closed tuxgvf closed 1 year ago

tuxgvf commented 4 years ago

There is a problem with this line in the arduino SCPI dimmer

my_instrument.SetCommandTreeBase(F("SYSTem:LED") ; // missing a close bracket and a &something

Any plan for python sample code?

Any plan for compatibility with NImax/ Keysight connection expert?

Vrekrer commented 4 years ago

Hi. thanks for the bug report.

There is indeed a missing close bracket. Fixed in last commit (9ad70e1)

Keysight connection expert detects the instruments if a query to *IDN? returns a string in the format : "Vendor,Instrument name,Serial number,Software version". (It works for me)

For Python you need PyVisa installed (+ pyvisa-py on Linux) You need to set the appropriate write and read terminations There is some python sample code at the end of the Ethernet example

Here is an example for the dimmer, using IPython.

In [1]: import visa

In [2]: rm = visa.ResourceManager('@py')

In [3]: rm.list_resources()
Out[3]: ('ASRL/dev/ttyACM0::INSTR',)

In [4]: VI = rm.get_instrument(Out[3][0])

In [5]: VI.write_termination = '\n'

In [6]: VI.read_termination = '\r\n'

In [7]: VI.query('*IDN?')
Out[7]: 'Vrekrer,Arduino SCPI Dimmer,#00,v0.4'

In [8]: VI.write('SYST:LED:BRIG 5')
Out[8]: (16, <StatusCode.success: 0>)

In [9]: VI.query('SYST:LED:BRIG?')
Out[9]: '5'
tuxgvf commented 4 years ago

I'm confused, how is it possible to connect such an arduino using Ethernet, is there a shield? Or Which arduino are you talking about? Is there a way to use it using serial connection using only USB? If yes how in python? How to configure the serial write_termination, termination and so on? Many thanks, I'm very interesting by your project!!!

Vrekrer commented 4 years ago

For Ethernet you can use : ENC28J60 based hardware (which uses EtherCard.h) or the Arduino Ethernet shield (uses Ethernet.h)

In both cases you need to configure your hardware to listen to port 5025 (default port for SCPI instrumentation)

For ENC28J60 hardware you need to code a function to get the message and then process it with the "Execute" procedure. See the Ethernet example and https://github.com/Vrekrer/Vrekrer_Voltmeter for examples.

For the Arduino Ethernet shield the configuration is easier, and uses a lot less memory. Configure the server: (global variables) EthernetServer server = EthernetServer(5025); //SCPI PORT (setup) Ethernet.begin(mac, ip, dns, gateway, subnet); server.begin(); Process the input: (use the stream interface) (loop) EthernetClient client = server.available(); if (client) { my_instrument.ProcessInput(client, "\n"); }

The visa string for the instrument is TCPIP0::<IP>::5025::SOCKET

tuxgvf commented 4 years ago

And what about in python using serial command?

Vrekrer commented 4 years ago

Is better to use a “Virtual Instrument Software Architecture” (VISA) library to communicate to a SCPI instrument. In python you can use PyVISA-py or the VISA library form Keysight or National instruments and PyVISA

If you want to use a low level library as pyserial just sent text messages as you would do in the Arduino IDE serial monitor.

tuxgvf commented 4 years ago

Yes this is exaclty what I want to do, but for now I can only scan the GPIB, usb instrument list, but I can't established a serial com between my arduino let's say uno or nano and my python 2.7

Vrekrer commented 4 years ago

If you can upload your sketch or use the serial monitor in the Arduino IDE, then your serial hardware is working. On windows the VISA resource name is ASRL#::INSTR were # is the same port number you are using in the Arduino IDE. If you still have problems, check the baud rate and parity bits configurations.

tuxgvf commented 4 years ago

I can't upload it on 1.0.4 and 1.6.5 arduino IDE which version do you recommand?

Vrekrer commented 4 years ago

https://www.arduino.cc/en/guide/troubleshooting#toc1

tuxgvf commented 4 years ago

Thanks for the link, but I got troubles while compiling and verify for error in the .c/.h file so that's why I'm asking for which version are you using or the arduino IDE? I made or to run another github scpi parser on arduino and made a python script and connection expert too. But for now i'm stuck with the.c file that generates me errors using 1.6.5 IDE version.

Metaln00b commented 4 years ago

For Ethernet you can use : ENC28J60 based hardware (which uses EtherCard.h) or the Arduino Ethernet shield (uses Ethernet.h)

In both cases you need to configure your hardware to listen to port 5025 (default port for SCPI instrumentation)

For ENC28J60 hardware you need to code a function to get the message and then process it with the "Execute" procedure. See the Ethernet example and https://github.com/Vrekrer/Vrekrer_Voltmeter for examples.

For the Arduino Ethernet shield the configuration is easier, and uses a lot less memory. Configure the server: (global variables) EthernetServer server = EthernetServer(5025); //SCPI PORT (setup) Ethernet.begin(mac, ip, dns, gateway, subnet); server.begin(); Process the input: (use the stream interface) (loop) EthernetClient client = server.available(); if (client) { my_instrument.ProcessInput(client, "\n"); }

The visa string for the instrument is TCPIP0::<IP>::5025::SOCKET

Could you please create a source example, how to use the Ethernet.h with your library? I have problems by using GetEthMsg() in combination with client.read(). There are many other points that become superfluous.

Vrekrer commented 4 years ago

Hi

here is an example. https://gist.github.com/Vrekrer/0f0bbc0cb9696ec8748b4ddfef425f06#file-volmeter-ino it uses the Stream interface, so it uses the same code for Serial and Ethernet. This example is the same as https://github.com/Vrekrer/Vrekrer_Voltmeter but using the Ethernet shield.

Right now I don't have time or the hardware to test a new Ethernet example. Later I will upload a simple example to this library.

Metaln00b commented 4 years ago

Hi

here is an example. https://gist.github.com/Vrekrer/0f0bbc0cb9696ec8748b4ddfef425f06#file-volmeter-ino it uses the Stream interface, so it uses the same code for Serial and Ethernet. This example is the same as https://github.com/Vrekrer/Vrekrer_Voltmeter but using the Ethernet shield.

Right now I don't have time or the hardware to test a new Ethernet example. Later I will upload a simple example to this library.

I've got it working. Thank you.

#include "Arduino.h"
#include "EEPROM.h"
#include <Ethernet.h>
#include "Vrekrer_scpi_parser.h"

const int eeprom_eth_data_start = 0;
const static byte dns[] = {0, 0, 0, 0};
const static byte mask[] = {255, 255, 255, 0};
byte mac[6] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
byte ip[4] = {192, 168, 13, 7};
byte gw[4] = {0, 0, 0, 0};

SCPI_Parser my_instrument;
boolean fromSerial = true;

EthernetServer server = EthernetServer(5025);
EthernetClient client;

void setup() {
  Serial.begin(9600);
  Ethernet.begin(mac, ip, dns, gw, mask);
  server.begin();

  my_instrument.RegisterCommand("*IDN?", &Identify);
  my_instrument.SetCommandTreeBase("SYSTem:COMMunicate:LAN"); 
    my_instrument.RegisterCommand(":ADDRess", &SetIP);
    my_instrument.RegisterCommand(":ADDRess?", &GetIP);
    my_instrument.RegisterCommand(":DGATeway", &SetGW);
    my_instrument.RegisterCommand(":DGATeway?", &GetGW);
    my_instrument.RegisterCommand(":MAC", &SetMAC);
    my_instrument.RegisterCommand(":MAC?", &GetMAC);

  int eeprom_address = eeprom_eth_data_start;
  if (EEPROM.read(eeprom_address) == 'V') { //Already initialized
    //Serial.println("EEPROM OK");
    ++eeprom_address;
    EEPROM.get(eeprom_address, mac);
    eeprom_address += sizeof(mac);
    EEPROM.get(eeprom_address, ip);
    eeprom_address += sizeof(ip);
    EEPROM.get(eeprom_address, gw);
  } else { //Write default values to EEPROM
    EEPROM.write(eeprom_address, 'V');
    ++eeprom_address;
    EEPROM.put(eeprom_address, mac);
    eeprom_address += sizeof(mac);
    EEPROM.put(eeprom_address, ip);
    eeprom_address += sizeof(ip);
    EEPROM.put(eeprom_address, gw);
  }
  while (!Serial);
}

void loop() {
  char *newline = strdup("\n");
  my_instrument.ProcessInput(Serial, newline);

  client = server.available();
  if(client) {
    my_instrument.ProcessInput(client, newline);  
  };
}

/* SCPI FUNCTIONS */

void Identify(SCPI_C commands __attribute__((unused)), SCPI_P parameters __attribute__((unused)), Stream &interface) {
  interface.print(F("MagDynLab,VrekrerVoltMeter,SN01,V.1.0\n"));
}

void SetIP(SCPI_C commands __attribute__((unused)), SCPI_P parameters, Stream &interface __attribute__((unused))) {
  SaveIP(parameters.First(), eeprom_eth_data_start + 7 );
}

void GetIP(SCPI_C commands __attribute__((unused)), SCPI_P parameters __attribute__((unused)), Stream &interface) {
  interface.print(Ethernet.localIP());
  interface.print("\n");
}

void SetGW(SCPI_C commands __attribute__((unused)), SCPI_P parameters, Stream &interface __attribute__((unused))) {
  SaveIP(parameters.First(), eeprom_eth_data_start + 11 );
}

void GetGW(SCPI_C commands __attribute__((unused)), SCPI_P parameters __attribute__((unused)), Stream &interface) {
  interface.print(Ethernet.gatewayIP());
  interface.print("\n");
}

void SetMAC(SCPI_C commands __attribute__((unused)), SCPI_P parameters, Stream &interface __attribute__((unused))) {
  int this_mac[6];
  int mac_ok = 0;
  if (parameters.Size() == 6) {
    for (uint8_t i = 0; i < 6; i++) {
      mac_ok += sscanf(parameters[i], "%x", &this_mac[i]);
    }
  }
  int eeprom_address = eeprom_eth_data_start + 1;  
  if (mac_ok == 6) {
    for (uint8_t i = 0; i < 6; i++) {
      EEPROM.write(eeprom_address, byte(this_mac[i]));
      ++eeprom_address;
    }
  }
}

void GetMAC(SCPI_C commands __attribute__((unused)), SCPI_P parameters __attribute__((unused)), Stream &interface) {
  byte macBuffer[6];
  Ethernet.MACAddress(macBuffer);
  for (byte octet = 0; octet < 6; octet++) {
    interface.print("0x");
    interface.print(macBuffer[octet], HEX);
    if (octet < 5) {
      interface.print(", ");
    }
  }
  interface.print("\n");
}

/* HELPER FUNCTIONS */

void SaveIP(char* ip_str, int eeprom_address) {
  int this_ip[4];
  int ipOk = sscanf(ip_str, "%d.%d.%d.%d", &this_ip[0], &this_ip[1], &this_ip[2], &this_ip[3]);
  if (ipOk == 4) {
    for (uint8_t i = 0; i < 4; i++) {
      EEPROM.write(eeprom_address, byte(this_ip[i]));
      ++eeprom_address;
    }
  }
}
tuxgvf commented 4 years ago

Which version of arduino are you using? Because i still have some troubles with all examples files.

Metaln00b commented 4 years ago

Which version of arduino are you using? Because i still have some troubles with all examples files.

What kind of troubles do you have? I am using the current version of Arduino IDE.

tuxgvf commented 4 years ago

on IDE 1.8.13 release on the arduino dimmer example I got this error

C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\SCPI_Dimmer\SCPI_Dimmer.ino: In function 'void loop()': C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\SCPI_Dimmer\SCPI_Dimmer.ino:55:42: warning: ISO C++ forbids converting a string constant to 'char' [-Wwrite-strings] my_instrument.ProcessInput(Serial, "\n"); ^ C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp: In member function 'void SCPI_Parser::SetCommandTreeBase(const char)': C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp:171:40: warning: invalid conversion from 'const char' to 'char' [-fpermissive] SCPI_Commands tree_tokens(tree_base); ^ C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp:54:1: note: initializing argument 1 of 'SCPI_Commands::SCPI_Commands(char)' SCPI_Commands::SCPI_Commands(char message) { ^~~~~ C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp: In member function 'void SCPI_Parser::RegisterCommand(const char, SCPI_caller_t)': C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp:187:39: warning: invalid conversion from 'const char' to 'char' [-fpermissive] SCPI_Commands command_tokens(command); ^ C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp:54:1: note: initializing argument 1 of 'SCPI_Commands::SCPI_Commands(char)' SCPI_Commands::SCPI_Commands(char *message) { ^~~~~ Sketch uses 6728 bytes (20%) of program storage space. Maximum is 32256 bytes. Global variables use 456 bytes (22%) of dynamic memory, leaving 1592 bytes for local variables. Maximum is 2048 bytes.

On the Ethernet_instrument.ino I got this error Could you please clarify another point on the wiring for the Ethernet_instrument.ino, using the enc28j60 module. do I have to connect the CS wire of the module to the pin 8 or pin 10 of the arduino?

C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\Ethernet_Instrument\Ethernet_Instrument.ino:1:21: warning: extra tokens at end of #include directive

include "Arduino.h";

                 ^

C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\Ethernet_Instrument\Ethernet_Instrument.ino:2:20: warning: extra tokens at end of #include directive

include "EEPROM.h";

                ^

C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\Ethernet_Instrument\Ethernet_Instrument.ino:3:23: warning: extra tokens at end of #include directive

include "EtherCard.h";

                   ^

C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\Ethernet_Instrument\Ethernet_Instrument.ino: In function 'void loop()': C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\Ethernet_Instrument\Ethernet_Instrument.ino:60:42: warning: ISO C++ forbids converting a string constant to 'char' [-Wwrite-strings] my_instrument.ProcessInput(Serial, "\n"); ^ C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\Ethernet_Instrument\Ethernet_Instrument.ino: In function 'char GetEthMsg()': C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\Ethernet_Instrument\Ethernet_Instrument.ino:130:34: warning: invalid conversion from 'byte {aka unsigned char}' to 'char' [-fpermissive] char msg = Ethernet::buffer + pos;


C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\Ethernet_Instrument\Ethernet_Instrument.ino: In function 'void IpToString(byte*, char*)':
C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\examples\Ethernet_Instrument\Ethernet_Instrument.ino:165:10: warning: return-statement with a value, in function returning 'void' [-fpermissive]
   return ip_str;
          ^~~~~~
C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp: In member function 'void SCPI_Parser::SetCommandTreeBase(const char*)':
C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp:171:40: warning: invalid conversion from 'const char*' to 'char*' [-fpermissive]
     SCPI_Commands tree_tokens(tree_base);
                                        ^
C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp:54:1: note:   initializing argument 1 of 'SCPI_Commands::SCPI_Commands(char*)'
 SCPI_Commands::SCPI_Commands(char *message) {
 ^~~~~~~~~~~~~
C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp: In member function 'void SCPI_Parser::RegisterCommand(const char*, SCPI_caller_t)':
C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp:187:39: warning: invalid conversion from 'const char*' to 'char*' [-fpermissive]
   SCPI_Commands command_tokens(command);
                                       ^
C:\Users\vi\Documents\Arduino\libraries\Vrekrer_scpi_parsermaster\src\Vrekrer_scpi_parser.cpp:54:1: note:   initializing argument 1 of 'SCPI_Commands::SCPI_Commands(char*)'
 SCPI_Commands::SCPI_Commands(char *message) {
 ^~~~~~~~~~~~~
C:\Users\vi\Documents\Arduino\libraries\EtherCard\src\dhcp.cpp: In function 'send_dhcp_message':
C:\Users\vi\Documents\Arduino\libraries\EtherCard\src\dhcp.cpp:165:11: warning: 'memset' writing 278 bytes into a region of size 128 overflows the destination [-Wstringop-overflow=]
     memset(gPB, 0, UDP_DATA_P + sizeof( DHCPdata ));
           ^
Sketch uses 14494 bytes (44%) of program storage space. Maximum is 32256 bytes.
Global variables use 897 bytes (43%) of dynamic memory, leaving 1151 bytes for local variables. Maximum is 2048 bytes.

Any idea? Thanks 
tuxgvf commented 4 years ago

Finally the Dimmer is working, but I still faced hard time to communicate with the Ethernet code. I can talk to the arduino in the Serial Monitor but I can't talk to him using NImax or Keysight IO lib. Do you have any idea why? I can't also ping the ip address using cmd command

Metaln00b commented 4 years ago

Finally the Dimmer is working, but I still faced hard time to communicate with the Ethernet code. I can talk to the arduino in the Serial Monitor but I can't talk to him using NImax or Keysight IO lib. Do you have any idea why? I can't also ping the ip address using cmd command

Sorry, but i am using a different ethernet shield. I am currently using the original arduino ethernet shield 2 with an W5500.

Vrekrer commented 4 years ago

For Ethernet you must use a RAW SOCKET connection to port 5025. Autodetection does not work, you must enter it manually. The visa string is TCPIP0::<IP>::5025::SOCKET For NImax or Keysight IO lib you might need to set the correct read and write terminations.

Metaln00b commented 4 years ago

To remove the compile errors, just remove "my_instrument.ProcessInput(Serial, newline);"

Metaln00b commented 4 years ago

There is an another problem. Unfortunately it does not work as expected.

If i simply enter "?" in serial, the return is Vrekrer,Arduino SCPI Dimmer,#00,v0.4