// agilentscope.c - GNU g++ egcs-2.91.66, V. Bancroft  1999 
//Fixed to run on ubuntu linux 2018 
//src from documentation. --fixed errors
#include <stdlib.h>
#include <string.h>
#include <stdio.h>     // ISO C Standard: 4.9 INPUT/OUTPUT 
#include <time.h>      // ISO C Standard: 4.12 DATE and TIME  
#include <termios.h>   // POSIX Standard: 7.1-2 General Terminal Intf. 
#include <unistd.h>    // POSIX Standard: 2.10 Symbolic Constants   
#include <fcntl.h>     // POSIX Standard: 6.5 File Control Operations 
#include <sys/types.h> // POSIX Standard: 2.6 Primitive System Data Types 
#include <sys/stat.h>  // POSIX Standard: 5.6 File Characteristics 
                       
#define DWORD                size_t 
// a file handle is an integer descriptor, 
#define HANDLE               int 
// open failure results in negative one, 
#define INVALID_HANDLE_VALUE -1 
// default device string 
#define DEVICE               "/dev/ttyUSB0" 
// define values for iSerOK 
#define TRUE                 1             
#define FALSE                0 
HANDLE   hSerPort;     // Global variables 
int      iSerOK; 
void SerMessage(char* msg1, char* msg2) 
// Displays a message to the user. 
// msg1 = main message 
// msg2 = message caption 
// Change this to your preferred way of displaying msgs. 
{ 
  printf( "%s ( %s )\n", msg1, msg2); 
} 
void SerCrash(char* msg1, char* msg2) 
// Like SerMessage, but ends the program. 
{ 
  SerMessage(msg1,msg2); 
  iSerOK = 0; 
} 
int SerOK() 
// Returns nonzero if most recent operation succeeded, 
// or 0 if there was an error 
{ 
  return iSerOK; 
} 
void SerOpen(char* portname, char* handshake) 
// Opens the serial port. 
// portname = "COM1", "COM2", etc. 
// handshake = "RTS" or "DTR" 
{ 
  // 
  // Open the port using a handle 
  // 
  hSerPort = open( portname, O_RDWR ); 
  if (hSerPort == INVALID_HANDLE_VALUE) { 
    SerCrash("Can't open comm port",portname); 
    iSerOK = FALSE; 
  } 

  struct termios term; 
  if ( tcgetattr( hSerPort, &term ) ) { 
    SerMessage( "Can't get device settings.", "tcgetattr"); 
    iSerOK = FALSE; 
  } 
  // Now choose the handshaking mode... 
  if ((handshake[0] == 'r') || (handshake[0] == 'R')) 
  { 
    term.c_cflag =  CRTSCTS;    // RTS/CTS flow control of output 
  } 
  else 
  { 
    term.c_cflag &=  ~( CRTSCTS ); // disable CTS flow control of output 
  } 
  // 
  // Set baud rate and other attributes 
  // 
  term.c_cflag |=   CS8;      // eight bit character set 
  term.c_cflag |=  CREAD;    // enable receiver 
  term.c_cflag |=  HUPCL;    // lower modem lines on last close 
  term.c_cflag |=  CLOCAL;   // ignore modem status lines 
  term.c_iflag = 0;          // turn off input processing 
  // term.c_iflag = IGNPAR;     // ignore parity errors 
  term.c_lflag = 0;          // turn off local processing 
  term.c_oflag = 0;          // turn off output processing 
  
cfsetispeed( &term, B9600 ); 
  cfsetospeed( &term, B9600 ); 
  if (tcsetattr( hSerPort, TCSANOW, &term )) { 
    SerCrash("Bad parameters for port",portname); 
    iSerOK = FALSE; 
  } 
  if (!iSerOK) SerCrash("Bad parameters for port",portname); 
  // 
  // Disable Windows' timeouts; we keep track of our own 
  // 
  // COMMTIMEOUTS t = {MAXDWORD,0,0,0,0}; 
  // SetCommTimeouts(hSerPort,&t); 
} 
void SerClose() 
// Closes the serial port. 
{ 
  iSerOK != close(hSerPort); 
  if (!iSerOK) SerCrash("Problem closing serial port",""); 
} 
void SerPut(char* data) 
// Transmits a line followed by CR and LF. 
// Caution!  Will wait forever, without registering an error, 
// if handshaking signals tell it not to transmit. 
{ 
  DWORD nBytes; 
  iSerOK =  nBytes=write(hSerPort,(const void *)data,strlen(data)); 
  iSerOK &= nBytes=write(hSerPort,"\r\n",2); 
  if (!iSerOK) SerCrash("Problem writing to serial port",""); 
} 
void SerGetChar(char* c, int* success) 
// Receives a character from the serial port, 
// or times out after 10 seconds. 
// success = 0 if timeout, 1 if successful 
{ 
  time_t finish; 
  finish = time(NULL) + 10; 
  *success = 0; 
  DWORD nBytes = 0; 
  while ((*success == 0) && (time(NULL) < finish)) { 
    nBytes=read(hSerPort,c,(size_t)1); 
    *success = nBytes; 

  } 
  if (*success == 0) 
    SerCrash("Timed out waiting for serial input",""); 
} 
void SerGet(char* buf, int bufsize) 
// Inputs a line from the serial port, stopping at 
// end of line, carriage return, timeout, or buffer full. 
{ 
  int bufpos = 0; 
  buf[bufpos] = 0;    // initialize empty string 
  int bufposmax = bufsize-1;  // maximum subscript 
  char c = 0; 
  int success = 0; 
// 
  // Eat any Return or Line Feed characters 
  // left over from end of previous line 
  // 
  do { SerGetChar(&c,&success); } 
  while ((success == 1) && (c <= 31)); 
  // 
  // We have now read the first character or timed out. 
  // Read characters until any termination condition is met. 
  // 
  while (1) { 
    if (success == 0) return;         // timeout 
    if (c == 13) return;              // carriage return 
    if (c == 10) return;              // line feed 
    if (bufpos >= bufposmax) return;  // buffer full 
    buf[bufpos] = c; 
    bufpos++; 
    buf[bufpos] = 0;  // guarantee validly terminated string 
    SerGetChar(&c,&success); 
  } 
} 
void SerGetNum(double* x) 
// Reads a floating-point number from the serial port. 
{ 
   char buf[20]; 
   SerGet(buf,sizeof(buf)); 
   iSerOK = sscanf(buf,"%lf",x);   // "%lf" = "long float" = double 
   if (iSerOK < 1) { 
     SerCrash("Problem converting string to number",buf); 
     *x = 0.0; 
   } 
} 
// Sample main program to conduct dialogue 
// with Agilent 54645D oscilloscope, 
// 9600 baud, DTR handshaking 
int main() 
{ 
 char b[20]; 
 double x; 
 // Sample dialogue for Agilent 64645D oscilloscope 
 SerOpen("/dev/ttyUSB0","RTS");   // note RTS handshaking 
 SerPut("*RST"); 
 SerPut("*CLS"); 
 SerPut(":SYSTEM:DSP 'Communicating with computer'"); 
 SerPut(":AUTOSCALE"); 
 SerPut(":MEASURE:VRMS? ANALOG1"); 
 SerGetNum(&x); 
 printf( "Channel 1 RMS voltage (as number) = %f\n", x ); 
 // cout << "Channel 1 RMS voltage (as number) = " << x << "\n"; 
 SerPut(":MEASURE:VPP? ANALOG2"); 
 SerGet(b,sizeof(b)); 
 printf( "Channel 2 P-P voltage (as string) = %s\n", b ); 
 // cout << "Channel 2 P-P voltage (as string) = " << b << "\n"; 
/* 
// Sample dialogue for Agilent 34401A multimeter 
 SerOpen("COM1","DTR");   // note DTR handshaking 
 SerPut(":SYST:REM"); 
 SerPut("*RST"); 
 SerPut("*CLS"); 
 SerPut(":DISP:TEXT 'OK'"); 
 SerPut(":MEASURE:VOLT:DC?"); 
 SerGetNum(&x); 
 printf( "Voltage (as number) = %d\n", x ); 
 // cout << "Voltage (as number) = " << x << "\n"; 
 SerPut(":MEASURE:VOLT:DC?"); 
 SerGet(b,sizeof(b)); 
 printf( "Voltage (as string) = %s\n", b ); 
 // cout << "Voltage (as string) = " << b << "\n"; 
*/ 
 // Say goodbye 
 printf( "Press Enter..."); 
 scanf("\r"); 
  SerClose(); 
 return 0; 
}