add pty-gpib-emulator from github
This commit is contained in:
parent
63554da593
commit
3fe71a6f3b
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
#include "Device.h"
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
string Device::handleCMD(Interface *fpl,
|
||||||
|
string cmd,
|
||||||
|
vector<string> *args) {
|
||||||
|
std::cout << "$$ Device: " << cmd << std::endl;
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
#ifndef DEVICE
|
||||||
|
#define DEVICE
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class Device;
|
||||||
|
|
||||||
|
#include "PTY_Interface.h"
|
||||||
|
#include <vector>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class Device {
|
||||||
|
public:
|
||||||
|
virtual string handleCMD(Interface *fpl,
|
||||||
|
string cmd,
|
||||||
|
vector<string> *args) {
|
||||||
|
return "";
|
||||||
|
} /**/
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,28 @@
|
||||||
|
CC=g++
|
||||||
|
CFLAGS=-c -std=c++11
|
||||||
|
LDFLAGS=
|
||||||
|
LIBRARIES=-lutil -lboost_system
|
||||||
|
SOURCES=PTY_Interface.cpp Prologix.cpp
|
||||||
|
OBJECTS=$(SOURCES:.cpp=.o)
|
||||||
|
EXECUTABLE=
|
||||||
|
|
||||||
|
TEST_SRC=$(SOURCES) test.cpp
|
||||||
|
TEST_OBJ=$(TEST_SRC:.cpp=.o)
|
||||||
|
TEST_EXE=test
|
||||||
|
|
||||||
|
all: $(SOURCES) $(OBJECTS)
|
||||||
|
|
||||||
|
test: $(TEST_SRC) $(TEST_OBJ)
|
||||||
|
|
||||||
|
$(TEST_EXE):
|
||||||
|
$(CC) $(LDFLAGS) $(TEST_OBJ) $(LIBRARIES) -o $(TEST_EXE)
|
||||||
|
|
||||||
|
$(EXECUTABLE): $(OBJECTS)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJECTS) -o $@
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CC) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *.o *~ *.gch
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
|
||||||
|
#include "PTY_Interface.h"
|
||||||
|
#include <pty.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <termios.h>
|
||||||
|
using namespace boost::algorithm;
|
||||||
|
|
||||||
|
static void set_noecho(int fd) { // Turn off Slave echo
|
||||||
|
struct termios stermios;
|
||||||
|
|
||||||
|
if (tcgetattr(fd, &stermios) < 0)
|
||||||
|
std::cout << "Error tcgetattr()" << std::endl;
|
||||||
|
|
||||||
|
stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||||
|
stermios.c_oflag &= ~(ONLCR);
|
||||||
|
/* also turn off NL to CR/NL mapping on output */
|
||||||
|
|
||||||
|
if (tcsetattr(fd, TCSANOW, &stermios) < 0)
|
||||||
|
std::cout << "Error tcsetattr()" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Interface::Interface(Device *default_device,
|
||||||
|
int default_address) {
|
||||||
|
char name[40];
|
||||||
|
|
||||||
|
this->addr = default_address;
|
||||||
|
this->addDevice(default_device, default_address);
|
||||||
|
|
||||||
|
if (openpty(&this->m, &this->s, name, NULL, NULL) < 0)
|
||||||
|
std::cerr << "Could not open pty device" << std::endl;
|
||||||
|
else {
|
||||||
|
set_noecho(this->s);
|
||||||
|
this->pname = name;
|
||||||
|
this->running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Interface::~Interface() {
|
||||||
|
close(this->m);
|
||||||
|
}
|
||||||
|
|
||||||
|
string Interface::printFilename() {
|
||||||
|
std::cout << this->pname << std::endl;
|
||||||
|
return this->pname;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interface::run(int readLen) {
|
||||||
|
char *tty_in = new char[readLen+1];
|
||||||
|
vector<string> tty_out;
|
||||||
|
string tty_full;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
this->running = true;
|
||||||
|
while (this->running) {
|
||||||
|
tty_full = "";
|
||||||
|
while (read(this->m, tty_in, readLen) >= readLen) {
|
||||||
|
std::cout << tty_in << std::endl;
|
||||||
|
tty_full += tty_in;
|
||||||
|
}
|
||||||
|
tty_full += tty_in;
|
||||||
|
i = tty_full.find("\n");
|
||||||
|
if ( i != string::npos )
|
||||||
|
tty_full = tty_full.substr(0, i);
|
||||||
|
|
||||||
|
tty_out = this->handleInput(tty_full);
|
||||||
|
for (std::vector<string>::iterator it = tty_out.begin();
|
||||||
|
it != tty_out.end();
|
||||||
|
it++) {
|
||||||
|
write(this->m, it->c_str(), it->length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] tty_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<string> Interface::handleInput(string tty_in) {
|
||||||
|
vector<string> out;
|
||||||
|
Device *dev = NULL;
|
||||||
|
vector<string> cmd;
|
||||||
|
vector<string> p;
|
||||||
|
string first;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
trim(tty_in);
|
||||||
|
if (tty_in != "" && this->devices.count(this->addr) > 0) {
|
||||||
|
dev = this->devices.at(this->addr);
|
||||||
|
if (dev == NULL) {
|
||||||
|
out.push_back("ERROR! No Device at address: " +
|
||||||
|
to_string(this->addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::split(cmd, tty_in, boost::is_any_of(";\n"));
|
||||||
|
for (i=0;i<cmd.size();i++) {
|
||||||
|
boost::split(p, cmd.at(i), boost::is_any_of(" "));
|
||||||
|
first = p.at(0);
|
||||||
|
p.erase(p.begin());
|
||||||
|
out.push_back(dev->handleCMD(this, first, &p) + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.push_back("");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interface::addDevice(Device *dev, int addr) {
|
||||||
|
this->devices.insert( std::pair<int, Device*>(addr, dev));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PTY_INTERFACE
|
||||||
|
#define PTY_INTERFACE
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class Interface;
|
||||||
|
|
||||||
|
#include "Device.h"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class Interface {
|
||||||
|
public:
|
||||||
|
map<int, Device*> devices;
|
||||||
|
int addr, m, s;
|
||||||
|
bool running;
|
||||||
|
string pname;
|
||||||
|
|
||||||
|
Interface(Device *default_device=NULL,
|
||||||
|
int default_address=0);
|
||||||
|
~Interface();
|
||||||
|
|
||||||
|
string printFilename();
|
||||||
|
void run(int readLen=100);
|
||||||
|
|
||||||
|
vector<string> handleInput(string tty_in);
|
||||||
|
void addDevice(Device *dev, int addr);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,66 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include "Prologix.h"
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
Prologix_GPIB_USB::Prologix_GPIB_USB() {
|
||||||
|
this->addCMD("++ver", &Prologix_GPIB_USB::version);
|
||||||
|
this->addCMD("++addr", &Prologix_GPIB_USB::addr);
|
||||||
|
this->addCMD("++kill", &Prologix_GPIB_USB::kill);
|
||||||
|
}
|
||||||
|
|
||||||
|
Prologix_GPIB_USB::~Prologix_GPIB_USB() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
string Prologix_GPIB_USB::handleCMD(Interface *fpl,
|
||||||
|
string cmd,
|
||||||
|
vector<string> *args) {
|
||||||
|
string out = "";
|
||||||
|
handler h;
|
||||||
|
|
||||||
|
if (out != "") {
|
||||||
|
return out;
|
||||||
|
} else if ( this->cmds.count(cmd) > 0 ) {
|
||||||
|
h = this->cmds.at(cmd);
|
||||||
|
return (this->*h)(fpl, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
string Prologix_GPIB_USB::version(Interface *fpl,
|
||||||
|
vector<string> *args) {
|
||||||
|
return "Prologix Version 1.1 Simulator (C++)";
|
||||||
|
}
|
||||||
|
|
||||||
|
string Prologix_GPIB_USB::addr(Interface *fpl,
|
||||||
|
vector<string> *args) {
|
||||||
|
if (args == NULL || args->size() == 0) {
|
||||||
|
return std::to_string(fpl->addr);
|
||||||
|
} else {
|
||||||
|
fpl->addr = atoi(args->at(0).c_str());
|
||||||
|
if ( fpl->devices.count(fpl->addr) == 0 )
|
||||||
|
fpl->addDevice(this, fpl->addr);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string Prologix_GPIB_USB::kill(Interface *fpl,
|
||||||
|
vector<string> *args) {
|
||||||
|
fpl->running = false;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Prologix_GPIB_USB::addCMD(const char *cmd, handler h) {
|
||||||
|
this->cmds.insert( std::pair<string, handler>(cmd, h) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Prologix_GPIB_USB::addCMD(string cmd, handler h) {
|
||||||
|
this->cmds.insert( std::pair<string, handler>(cmd, h) );
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PROLOGIX
|
||||||
|
#define PROLOGIX
|
||||||
|
|
||||||
|
#include "Device.h"
|
||||||
|
#include <map>
|
||||||
|
#include "PTY_Interface.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Prologix_GPIB_USB : public Device {
|
||||||
|
public:
|
||||||
|
typedef string (Prologix_GPIB_USB::*handler)(Interface *fpl,
|
||||||
|
vector<string> *args);
|
||||||
|
map<string, handler> cmds;
|
||||||
|
|
||||||
|
Prologix_GPIB_USB();
|
||||||
|
~Prologix_GPIB_USB();
|
||||||
|
|
||||||
|
string handleCMD(Interface *fpl, string cmd, vector<string> *args);
|
||||||
|
string version(Interface *fpl, vector<string> *args);
|
||||||
|
string addr(Interface *fpl, vector<string> *args);
|
||||||
|
string kill(Interface *fpl, vector<string> *args);
|
||||||
|
|
||||||
|
void addCMD(const char *cmd, handler h);
|
||||||
|
void addCMD(string cmd, handler h);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include "PTY_Interface.h"
|
||||||
|
#include "Prologix.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define TEST(A) std::cout << A << ": " << inter.handleInput(A).at(0) << std::endl;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Prologix_GPIB_USB *plg = new Prologix_GPIB_USB();
|
||||||
|
Interface inter(plg);
|
||||||
|
vector<string> v;
|
||||||
|
|
||||||
|
inter.printFilename();
|
||||||
|
inter.addDevice(plg, 0);
|
||||||
|
|
||||||
|
TEST("++ver");
|
||||||
|
TEST("++addr");
|
||||||
|
TEST("++addr 2");
|
||||||
|
TEST("++addr");
|
||||||
|
TEST("++ver");
|
||||||
|
|
||||||
|
inter.printFilename();
|
||||||
|
inter.run();
|
||||||
|
|
||||||
|
delete plg;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
CC=g++
|
||||||
|
CFLAGS=-c -std=c++11
|
||||||
|
LDFLAGS=
|
||||||
|
LIBRARIES=-lutil
|
||||||
|
SOURCES=MiddleMan.cpp simple.cpp
|
||||||
|
OBJECTS=$(SOURCES:.cpp=.o)
|
||||||
|
EXECUTABLE=simple
|
||||||
|
|
||||||
|
all: $(SOURCES) $(OBJECTS) $(EXECUTABLE)
|
||||||
|
|
||||||
|
|
||||||
|
$(EXECUTABLE): $(OBJECTS)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJECTS) -o $@ $(LIBRARIES)
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CC) $(CFLAGS) $< -o $@ $(LIBRARIES)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *.o *~ *.gch
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
|
||||||
|
#include "MiddleMan.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pty.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void setPort(int fd) {
|
||||||
|
/* *** Configure Port *** */
|
||||||
|
struct termios tty;
|
||||||
|
memset (&tty, 0, sizeof tty);
|
||||||
|
|
||||||
|
/* Error Handling */
|
||||||
|
if ( tcgetattr ( fd, &tty ) != 0 ) {
|
||||||
|
std::cout << "Error tcgetattr()" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set Baud Rate */
|
||||||
|
cfsetospeed (&tty, B9600);
|
||||||
|
cfsetispeed (&tty, B9600);
|
||||||
|
|
||||||
|
/* Setting other Port Stuff */
|
||||||
|
tty.c_cflag &= ~PARENB; // Make 8n1
|
||||||
|
tty.c_cflag &= ~CSTOPB;
|
||||||
|
tty.c_cflag &= ~CSIZE;
|
||||||
|
tty.c_cflag |= CS8;
|
||||||
|
tty.c_cflag &= ~CRTSCTS; // no flow control
|
||||||
|
|
||||||
|
// no signaling chars, no echo, no canonical processing
|
||||||
|
tty.c_lflag = 0;
|
||||||
|
tty.c_oflag = 0; // no remapping, no delays
|
||||||
|
tty.c_cc[VMIN] = 0; // read doesn't block
|
||||||
|
// 0.5 seconds read timeout
|
||||||
|
tty.c_cc[VTIME] = 5;
|
||||||
|
|
||||||
|
// turn on READ & ignore ctrl lines
|
||||||
|
tty.c_cflag |= CREAD | CLOCAL;
|
||||||
|
|
||||||
|
// turn off s/w flow ctrl
|
||||||
|
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||||
|
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
|
||||||
|
tty.c_oflag &= ~OPOST; // make raw
|
||||||
|
|
||||||
|
/* Flush Port, then applies attributes */
|
||||||
|
tcflush( fd, TCIFLUSH );
|
||||||
|
|
||||||
|
if ( tcsetattr ( fd, TCSANOW, &tty ) != 0) {
|
||||||
|
std::cout << "Error tcsetattr()" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void set_noecho(int fd) { // Turn off Slave echo
|
||||||
|
struct termios stermios;
|
||||||
|
|
||||||
|
if (tcgetattr(fd, &stermios) < 0)
|
||||||
|
std::cout << "Error tcgetattr()" << std::endl;
|
||||||
|
|
||||||
|
stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||||
|
stermios.c_oflag &= ~(ONLCR);
|
||||||
|
/* also turn off NL to CR/NL mapping on output */
|
||||||
|
|
||||||
|
if (tcsetattr(fd, TCSANOW, &stermios) < 0)
|
||||||
|
std::cout << "Error tcsetattr()" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
MiddleMan::MiddleMan(const string tty,
|
||||||
|
const string fout_name,
|
||||||
|
int sleepTime) {
|
||||||
|
char name[40];
|
||||||
|
|
||||||
|
if (openpty(&this->mPTY, &this->sPTY, name, NULL, NULL) < 0)
|
||||||
|
std::cerr << "Could not open pty device" << std::endl;
|
||||||
|
else {
|
||||||
|
set_noecho(this->sPTY);
|
||||||
|
this->ptyname = name;
|
||||||
|
this->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (this->mTTY = open(tty.c_str(), O_RDWR| O_NONBLOCK)) < 0 ) {
|
||||||
|
std::cerr << "Could not open tty device" << std::endl;
|
||||||
|
} else {
|
||||||
|
this->ttyname = tty;
|
||||||
|
setPort(this->mTTY);
|
||||||
|
}
|
||||||
|
if ( (this->fout = fopen(fout_name.c_str(), "w+")) == NULL )
|
||||||
|
std::cout << "Error upon opening the output file" << std::endl;
|
||||||
|
this->sleep = sleepTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
MiddleMan::~MiddleMan() {
|
||||||
|
close(this->mPTY);
|
||||||
|
fclose(this->fout);
|
||||||
|
}
|
||||||
|
|
||||||
|
string MiddleMan::getPTY() {
|
||||||
|
return this->ptyname;
|
||||||
|
}
|
||||||
|
|
||||||
|
string readTTY(int master, int readLen=100) {
|
||||||
|
char *tty_in = new char[readLen+1];
|
||||||
|
string tty_full;
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
tty_full = "";
|
||||||
|
while ((i=read(master, tty_in, readLen)) >= readLen) {
|
||||||
|
tty_in[i] = '\0';
|
||||||
|
tty_full += tty_in;
|
||||||
|
}
|
||||||
|
tty_in[i] = '\0';
|
||||||
|
tty_full += tty_in;
|
||||||
|
delete[] tty_in;
|
||||||
|
return tty_full;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiddleMan::run(int readLen) {
|
||||||
|
this->running = true;
|
||||||
|
while (this->running) {
|
||||||
|
this->handleInput(readTTY(this->mPTY, readLen));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiddleMan::handleInput(string tty_in) {
|
||||||
|
string buf;
|
||||||
|
|
||||||
|
write(this->mTTY, tty_in.c_str(), tty_in.size());
|
||||||
|
usleep(this->sleep); // microseconds
|
||||||
|
buf = readTTY(this->mTTY);
|
||||||
|
write(this->mPTY, buf.c_str(), buf.size());
|
||||||
|
this->log(tty_in, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MiddleMan::log(string input, string output,
|
||||||
|
const string format) {
|
||||||
|
printf(format.c_str(), input.c_str(), output.c_str());
|
||||||
|
fprintf(this->fout, format.c_str(), input.c_str(), output.c_str());
|
||||||
|
fflush(this->fout);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MIDDLEMAN
|
||||||
|
#define MIDDLEMAN
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class MiddleMan;
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class MiddleMan {
|
||||||
|
private:
|
||||||
|
string ttyname;
|
||||||
|
int mPTY, sPTY;
|
||||||
|
int mTTY, sTTY;
|
||||||
|
string ptyname;
|
||||||
|
bool running;
|
||||||
|
int sleep; // Microseconds
|
||||||
|
FILE *fout;
|
||||||
|
public:
|
||||||
|
MiddleMan(const string iotty_name,
|
||||||
|
const string fout_name="out",
|
||||||
|
int sleepTime=200);
|
||||||
|
~MiddleMan();
|
||||||
|
|
||||||
|
void run(int readLen=100);
|
||||||
|
|
||||||
|
string getPTY();
|
||||||
|
void handleInput(string input);
|
||||||
|
void log(string input, string output,
|
||||||
|
const string format=">> %s\n<< %s\n");
|
||||||
|
|
||||||
|
string openPTY();
|
||||||
|
void closePTY();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include "MiddleMan.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
std::cout << "Usage: " << argv[0] << " <tty device>" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MiddleMan m(argv[1]);
|
||||||
|
std::cout << m.getPTY() << std::endl;
|
||||||
|
m.run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
##
|
||||||
|
## **** Device Class ****
|
||||||
|
## by Aidan Macdonald (aidan.plenert.macdonald@gmail.com)
|
||||||
|
##
|
||||||
|
## Standard framework for the a Device that is attached
|
||||||
|
## to the PTY_Interface
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
class Device:
|
||||||
|
##
|
||||||
|
##%% No initialization
|
||||||
|
##
|
||||||
|
|
||||||
|
##%% handleCMD(pty_interface, command, arguments)
|
||||||
|
## A device attached to a PTY_Interface will handle commands
|
||||||
|
## passed to it from the PTY_Interface by a call made to
|
||||||
|
## this function.
|
||||||
|
##
|
||||||
|
## pty_interface will be a referance to the interface that called
|
||||||
|
## this function
|
||||||
|
##
|
||||||
|
## command will be a string with the text of the command read
|
||||||
|
## from the pty device
|
||||||
|
##
|
||||||
|
## arguments is an array of the arguments to said command read
|
||||||
|
## from the pty device
|
||||||
|
##
|
||||||
|
## The string returned by this function will be written to
|
||||||
|
## the pty device
|
||||||
|
##
|
||||||
|
def handleCMD(self, fpl, cmd, args=[]):
|
||||||
|
return ""
|
|
@ -0,0 +1,87 @@
|
||||||
|
##
|
||||||
|
## **** PTY_Interface Class ****
|
||||||
|
## by Aidan Macdonald (aidan.plenert.macdonald@gmail.com)
|
||||||
|
##
|
||||||
|
## This class generates a pty device that emulates the
|
||||||
|
## tty device created by GPIB controllers such as
|
||||||
|
## Prologix GPIB-USB Controller (prologix.biz)
|
||||||
|
##
|
||||||
|
## This class does NOT emulate the controller, but the
|
||||||
|
## controller must be attached to this PTY Interface
|
||||||
|
##
|
||||||
|
## I may switch between the terms tty device and pty device.
|
||||||
|
## They refer to the same thing.
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import Device, Prologix
|
||||||
|
|
||||||
|
class Interface:
|
||||||
|
|
||||||
|
##%% Initialization - Interface(default_device, default_address)
|
||||||
|
## accepts arguments default_device and default_address
|
||||||
|
## the default_device will be connected at the default_address
|
||||||
|
##
|
||||||
|
## If the Interface address (PTY_Interface.addr) is changed, the
|
||||||
|
## no longer have anything attached and will become functionless.
|
||||||
|
## UNLESS, the default device handles the address change and copies itself
|
||||||
|
## to the new address (Prologix_GPIB_USB does this, OR there is
|
||||||
|
## another device attached there.
|
||||||
|
##
|
||||||
|
## if no arguments are given at initialization, defaults are
|
||||||
|
## Device.Prologix_GPIB-USB at address 0
|
||||||
|
##
|
||||||
|
def __init__(self,
|
||||||
|
default_device=Prologix.Prologix_GPIB_USB(),
|
||||||
|
default_address=0 ):
|
||||||
|
self.m, self.s = os.openpty()
|
||||||
|
self.devices = {default_address:default_device}
|
||||||
|
self.addr = default_address
|
||||||
|
|
||||||
|
##%% printFilename()
|
||||||
|
## Prints the path to the PTY device generated (ie /dev/pts/2)
|
||||||
|
##
|
||||||
|
def printFilename(self):
|
||||||
|
name = os.ttyname(self.s)
|
||||||
|
print(name)
|
||||||
|
return name
|
||||||
|
|
||||||
|
##%% run(readLen)
|
||||||
|
## Runs the emulator which will read all statements written from the outside
|
||||||
|
## to the pty device at the location given by self.printFilename(), then
|
||||||
|
## runs what was read through self.handleInput(tty_in) and writes output
|
||||||
|
## back to the pty device to be read from the outside
|
||||||
|
##
|
||||||
|
def run(self, readLen=100):
|
||||||
|
self.running = True
|
||||||
|
while (self.running):
|
||||||
|
tty_in = os.read(self.m, readLen)
|
||||||
|
for tty_out in self.handleInput(tty_in):
|
||||||
|
os.write(self.m, tty_out)
|
||||||
|
|
||||||
|
|
||||||
|
##%% handleInput(tty_in)
|
||||||
|
## Recieves raw input that was read from the pty device, and
|
||||||
|
## breaks it up and send it to the device listed at the current
|
||||||
|
## address. That device must handle the command via dev.handleCMD(cmd, args)
|
||||||
|
##
|
||||||
|
def handleInput(self, tty_in):
|
||||||
|
tty_in = tty_in.strip()
|
||||||
|
|
||||||
|
if tty_in != "" and self.addr in self.devices:
|
||||||
|
dev = self.devices[self.addr]
|
||||||
|
for cmd in tty_in.strip().split(";"):
|
||||||
|
p = cmd.strip().split(" ")
|
||||||
|
yield dev.handleCMD(self, p[0], p[1:]) + "\n"
|
||||||
|
|
||||||
|
yield "" # Must be a null string to prevent infinite loop
|
||||||
|
|
||||||
|
##%% addDevice(device, address)
|
||||||
|
## Preferred way of connecting a device to the interface
|
||||||
|
## at a given address
|
||||||
|
##
|
||||||
|
def addDevice(self, dev, addr):
|
||||||
|
self.devices[addr] = dev
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
##
|
||||||
|
## <<<< Powersupply Emulators >>>>
|
||||||
|
## by Aidan Macdonald (aidan.plenert.macdonald@gmail.com)
|
||||||
|
##
|
||||||
|
## Contains classes that emulate powersupplies by
|
||||||
|
## building off the Device framework
|
||||||
|
##
|
||||||
|
|
||||||
|
import Device, Prologix
|
||||||
|
|
||||||
|
## **** Power Supply class ****
|
||||||
|
## by Aidan Macdonald (aidan.plenert.macdonald@gmail.com)
|
||||||
|
##
|
||||||
|
## General model of a basic Power Supply
|
||||||
|
##
|
||||||
|
|
||||||
|
class PowerSupply(Prologix.Prologix_GPIB_USB):
|
||||||
|
|
||||||
|
##%% Initialization PowerSupply(volt, current)
|
||||||
|
## Creates a framework for a Powersupply, but only binds
|
||||||
|
## a reset call to "RST?". All other functions have been
|
||||||
|
## left unbound so that children can bind them to respective
|
||||||
|
## commands
|
||||||
|
##
|
||||||
|
## voltage and current default to 10
|
||||||
|
##
|
||||||
|
def __init__(self, volt=10, cur=10):
|
||||||
|
Prologix.Prologix_GPIB_USB.__init__(self)
|
||||||
|
self.addCMD("RST?", self.reset)
|
||||||
|
|
||||||
|
self.voltage = volt
|
||||||
|
self.current = cur
|
||||||
|
|
||||||
|
##%% reset(pty, args)
|
||||||
|
## returns that the device has been reset
|
||||||
|
##
|
||||||
|
def reset(self, fpl, args=[]):
|
||||||
|
return "Power Supply has been reset"
|
||||||
|
|
||||||
|
##%% version(pty, args)
|
||||||
|
## overrides the version function from superclass
|
||||||
|
## left unbound here, because it was bound in the
|
||||||
|
## superclass.
|
||||||
|
##
|
||||||
|
def version(self, fpl, args=[]):
|
||||||
|
return "Power Supply Version 1.GEN"
|
||||||
|
|
||||||
|
##%% on(pty, args)
|
||||||
|
## turns power supply on
|
||||||
|
##
|
||||||
|
def on(self, fpl, args=[]):
|
||||||
|
return self.version(fpl, args) + " in now ON"
|
||||||
|
##%% off(pty, args)
|
||||||
|
## turns power supply off
|
||||||
|
##
|
||||||
|
def off(self, fpl, args=[]):
|
||||||
|
return self.version(fpl, args) + " in now OFF"
|
||||||
|
|
||||||
|
##%% getVoltage(pty, args)
|
||||||
|
## returns voltage
|
||||||
|
##
|
||||||
|
def getVoltage(self, fpl, args=[]):
|
||||||
|
return self.voltage
|
||||||
|
|
||||||
|
##%% getCurrent(pty, args)
|
||||||
|
## returns current
|
||||||
|
##
|
||||||
|
def getCurrent(self, fpl, args=[]):
|
||||||
|
return self.current
|
||||||
|
|
||||||
|
|
||||||
|
##%% setVoltage(pty, args)
|
||||||
|
## sets voltage
|
||||||
|
##
|
||||||
|
def setVoltage(self, fpl, args=[]):
|
||||||
|
try:
|
||||||
|
self.voltage = float(args[0])
|
||||||
|
return ""
|
||||||
|
except:
|
||||||
|
return "ERROR"
|
||||||
|
##%% setCurrent(pty, args)
|
||||||
|
## sets current
|
||||||
|
##
|
||||||
|
def setCurrent(self, fpl, args=[]):
|
||||||
|
try:
|
||||||
|
self.current = float(args[0])
|
||||||
|
return ""
|
||||||
|
except:
|
||||||
|
return "ERROR"
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## **** E3631A Power Supply Class ****
|
||||||
|
## by Aidan Macdonald (aidan.plenert.macdonald@gmail.com)
|
||||||
|
##
|
||||||
|
## Emulates the E3631A Power Supply
|
||||||
|
##
|
||||||
|
|
||||||
|
class E3631A(PowerSupply):
|
||||||
|
##%% Initialization - E3631A(voltage, current)
|
||||||
|
## see PowerSupply.PowerSupply documentation
|
||||||
|
##
|
||||||
|
## adds bindings for all of the PowerSupply functions
|
||||||
|
##
|
||||||
|
def __init__(self, volt=10, cur=10):
|
||||||
|
PowerSupply.__init__(self, volt, cur)
|
||||||
|
|
||||||
|
self.addCMD("OUTP", self.outp)
|
||||||
|
self.addCMD("MEAS:VOLT:DC", self.getVoltage)
|
||||||
|
self.addCMD("MEAS:CURR:DC", self.getCurrent)
|
||||||
|
self.addCMD("SET:VOLT:DC", self.setVoltage)
|
||||||
|
self.addCMD("SET:CURR:DC", self.setCurrent)
|
||||||
|
|
||||||
|
##%% version(pty, args)
|
||||||
|
## returns version
|
||||||
|
##
|
||||||
|
def version(self, fpl, args=[]):
|
||||||
|
return "E3631A Power Supply"
|
||||||
|
|
||||||
|
##%% outp(pty, args)
|
||||||
|
## function binding for the "OUTP" command
|
||||||
|
## Used to turn the device on and off
|
||||||
|
##
|
||||||
|
def outp(self, fpl, args=[]):
|
||||||
|
if args[0] == "ON":
|
||||||
|
return self.on(fpl, args)
|
||||||
|
elif args[0] == "OFF":
|
||||||
|
return self.off(fpl, args)
|
||||||
|
return ""
|
|
@ -0,0 +1,85 @@
|
||||||
|
##
|
||||||
|
## **** Prologix_GPIB_USB Class ****
|
||||||
|
##
|
||||||
|
## A Device that emulates the functionality of the
|
||||||
|
## Prologix GPIB-USB Controller (prologix.biz)
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
import Device, PTY_Interface
|
||||||
|
|
||||||
|
class Prologix_GPIB_USB(Device.Device):
|
||||||
|
|
||||||
|
##%% Initialization - Prologix_GPIB_USB()
|
||||||
|
## Does not take arguments, but is VERY important
|
||||||
|
## All classes that attempt to inherit this class,
|
||||||
|
## must call this initialization.
|
||||||
|
##
|
||||||
|
## This creates a dictionary containing all the commands
|
||||||
|
## to be run. If this dictionary is not created, this class
|
||||||
|
## does nothing
|
||||||
|
##
|
||||||
|
def __init__(self):
|
||||||
|
self.cmds = { "++ver":self.version, # "COMMAND":HANDLER
|
||||||
|
"++addr":self.addr,
|
||||||
|
"++kill":self.kill}
|
||||||
|
|
||||||
|
##%% handleCMD(pty_interface, command, arguments)
|
||||||
|
## See Device.handleCMD documentation
|
||||||
|
##
|
||||||
|
## In Prologix_GPIB_USB, this function makes use of the
|
||||||
|
## map made in initialization to find the command and
|
||||||
|
## its associated handler, then call the handler and pass in
|
||||||
|
## the pty_interface and the arguments
|
||||||
|
##
|
||||||
|
def handleCMD(self, fpl, cmd, args=[]):
|
||||||
|
out = Device.Device.handleCMD(self, fpl, cmd, args)
|
||||||
|
if out != "":
|
||||||
|
return out
|
||||||
|
elif cmd in self.cmds:
|
||||||
|
return self.cmds[cmd](fpl, args)
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
##%% version(pty, args)
|
||||||
|
## Returns the device version
|
||||||
|
##
|
||||||
|
def version(self, fpl, args=[]):
|
||||||
|
return "Prologix Version 1.1 Simulator (Python)"
|
||||||
|
|
||||||
|
##%% addr(pty, args)
|
||||||
|
## If no arguments are given, returns the current address
|
||||||
|
## of the pty interface
|
||||||
|
##
|
||||||
|
## if args are given, then an integer is parsed out of
|
||||||
|
## the first argument and set as the address. This ensures
|
||||||
|
## that a device exists at the following address
|
||||||
|
##
|
||||||
|
## Any errors return "ERROR"
|
||||||
|
##
|
||||||
|
def addr(self, fpl, args=[]):
|
||||||
|
if args == []:
|
||||||
|
return str(fpl.addr)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
fpl.addr = int(args[0])
|
||||||
|
if not fpl.addr in fpl.devices:
|
||||||
|
fpl.addDevice(PrologixAdapter(), fpl.addr)
|
||||||
|
return ""
|
||||||
|
except:
|
||||||
|
return "ERROR"
|
||||||
|
##%% kill(pty, args)
|
||||||
|
## Stops the pty interface from running
|
||||||
|
##
|
||||||
|
def kill(self, fpl, args=[]):
|
||||||
|
fpl.running = False
|
||||||
|
return ""
|
||||||
|
|
||||||
|
##%% addCMD(command, handler_function)
|
||||||
|
## Adds a command to the dictionary
|
||||||
|
## Handler function must be of the form
|
||||||
|
## func(pty_interface, arguments):
|
||||||
|
##
|
||||||
|
def addCMD(self, cmd, func):
|
||||||
|
self.cmds[cmd] = func
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
##
|
||||||
|
## <<<< Source Measurement Unit Emulators >>>>
|
||||||
|
## by Aidan Macdonald (aidan.plenert.macdonald@gmail.com)
|
||||||
|
##
|
||||||
|
## Contains classes that emulate Source Measurement Units
|
||||||
|
##
|
||||||
|
|
||||||
|
import Device, Prologix
|
||||||
|
|
||||||
|
## **** Source Measurement Class ****
|
||||||
|
## by Aidan Macdonald (aidan.plenert.macdonald@gmail.com)
|
||||||
|
##
|
||||||
|
## General model of a basic Source Measurement Unit
|
||||||
|
##
|
||||||
|
|
||||||
|
class SourceMeasurement(Prologix.Prologix_GPIB_USB):
|
||||||
|
|
||||||
|
##%% Initialization SourceMeasurement()
|
||||||
|
## Creates the framework
|
||||||
|
##
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Prologix.Prologix_GPIB_USB.__init__(self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## **** Keithley 2400 Class ****
|
||||||
|
## by Aidan Macdonald
|
||||||
|
##
|
||||||
|
## Support given for some commands
|
||||||
|
##
|
||||||
|
|
||||||
|
from random import uniform as rand
|
||||||
|
|
||||||
|
class Keithley_2400(SourceMeasurement):
|
||||||
|
|
||||||
|
##%% Initialization - Keithley_2400()
|
||||||
|
## Loads commands
|
||||||
|
##
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
SourceMeasurement.__init__(self)
|
||||||
|
self.addCMD("IDN?", self.version)
|
||||||
|
self.addCMD("*RST", self.noth)
|
||||||
|
self.addCMD("*CLS", self.noth)
|
||||||
|
self.addCMD("ABOR", self.noth)
|
||||||
|
self.addCMD("*CLS", self.noth)
|
||||||
|
self.addCMD("SYST:BEEP:STAT", self.noth)
|
||||||
|
self.addCMD("SOURCE:CLEAR:AUTO", self.noth)
|
||||||
|
self.addCMD("FORM:ELEM", self.noth)
|
||||||
|
self.addCMD(":SOUR:FUNC", self.noth)
|
||||||
|
self.addCMD("read?", self.randFloats)
|
||||||
|
|
||||||
|
## noth(pty, args)
|
||||||
|
## Does nothing
|
||||||
|
##
|
||||||
|
def noth(self, fpl, args):
|
||||||
|
pass # Do nothing
|
||||||
|
|
||||||
|
|
||||||
|
def version(self, fpl, args):
|
||||||
|
return 'KEITHLEY INSTRUMENTS INC.,MODEL 2400.EMULATOR'
|
||||||
|
|
||||||
|
## randFloats(pty, args)
|
||||||
|
## returns a string of random floats
|
||||||
|
##
|
||||||
|
def randFloats(self, fpl, args):
|
||||||
|
return str(rand(0, 2)) + ", " str(rand(0, 2))
|
||||||
|
|
||||||
|
## handleCMD(fpl, cmd, args)
|
||||||
|
## Modified to be case insensitive
|
||||||
|
##
|
||||||
|
def handleCMD(self, fpl, cmd, args):
|
||||||
|
SourceMeasurement.handleCMD(self, fpl, cmd.upper(), args)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import PTY_Interface
|
||||||
|
import PowerSupply
|
||||||
|
|
||||||
|
pty = PTY_Interface.Interface()
|
||||||
|
pty.addDevice(PowerSupply.PowerSupply(), 5)
|
||||||
|
pty.addDevice(PowerSupply.E3631A(), 3)
|
||||||
|
|
||||||
|
pty.printFilename()
|
||||||
|
pty.run()
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
NAME=`echo $1 | awk -F'.' '{ print $1 }'`
|
||||||
|
|
||||||
|
cat $1 | grep "##" | sed s/"##"//g | sed s/"\*\*"/"="/g | sed s/"<<<<"/"="/g | sed s/">>>>"/"="/g | sed s/"%%"/"*"/g > $2
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cat < $1 &
|
||||||
|
|
||||||
|
echo "++ver" > $1
|
||||||
|
echo "++addr" > $1
|
||||||
|
echo "++addr 12" > $1
|
||||||
|
echo "++addr" > $1
|
||||||
|
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
read CMD
|
||||||
|
echo $CMD > $1
|
||||||
|
done
|
Loading…
Reference in New Issue