gclib  2.0.8
Communications API for Galil controllers and PLCs
gcl_galil.cpp
Go to the documentation of this file.
1 
4 #include "gcl_galil.h"
5 using namespace std;
6 
7 
8 void ec(GReturn rc)
9 {
10 
11  switch (rc)
12  {
13  case G_NO_ERROR:
14  return;
15 
16  case G_TIMEOUT:
17  throw string("1010 TIMEOUT ERROR. Galil::command() took longer than timeout to return\n");
18  break;
19 
20  case G_OPEN_ERROR:
21  throw string("5002 OPEN ERROR. Galil::Galil() failed to open device\n");
22  break;
23 
25  throw string("7020 INVALID COMMAND ERROR. DL, ED, and QD are not allowed from Galil::command()\n");
26  break;
27 
29  throw string("6150 WRONG BUS ERROR. Galil::record(\"DR\") not supported on RS-232. Use Ethernet or Galil::record(\"QR\")\n");
30  break;
31 
33  throw string("6130 WRONG BUS ERROR. Galil::firmwareDownloadFile() isn't allowed via Ethernet. Use RS-232\n"); //21x3 etc.
34  break;
35 
37  throw string("7060 INVALID CHARACTER ERROR. Galil::programDownload() can't download program with backslash \\ character. Use {^92} in MG commands\n");
38  break;
39 
41  throw string("7061 INVALID LENGTH ERROR. Galil::programDownload() can't compress\n");
42  break;
43 
45  throw string("2010 COMMAND ERROR. Galil::command() got ? instead of : response.\n");
46  break;
47 
48  case G_BAD_FILE:
49  throw string("4000 FILE ERROR. Galil::Galil() failed to open file\n");
50  break;
51 
53  throw string("6000 WRONG BUG ERROR. Function isn't allowed on this bus\n");
54  break;
55 
56 
57  /*
58  case G_DATA_RECORD_ERROR:
59  case G_BAD_ADDRESS:
60  case G_BAD_LOST_DATA:
61  case G_BAD_VALUE_RANGE:
62  case G_BAD_FULL_MEMORY:
63  case G_ARRAY_NOT_DIMENSIONED:
64  case G_GCLIB_ERROR:
65  case G_GCLIB_UTILITY_ERROR:
66  case G_INVALID_PREPROCESSOR_OPTIONS:
67  */
68 
69  default: //couldn't find error map, make a gcl-like error from gclib error code
70  {
71  char buf[G_SMALL_BUFFER];
72  GError(rc, buf, sizeof(buf)); //get the error message
73  throw (to_string(rc) + " GCLIB ERROR. " + string(buf) + '\n');
74  }
75 
76  }//switch
77 }
78 
80 string AddressConvert(const string& gcl_address)
81 {
82  if (gcl_address.size() == 0) //this implementation does not present the user with a connections dialog if a nullstring is passed.
83  throw string("5005 OPEN ERROR. Null string specified in Galil::Galil()\n");
84 
85  if (gcl_address.find("OFFLINE") != string::npos)
86  throw string("5001 OPEN ERROR. OFFLINE specified to Galil::Galil()\n");
87 
88  vector<string> args;
89  size_t start = 0;
90  size_t i;
91  for (i = 0; i < gcl_address.size(); i++) //split into tokens
92  {
93  if (gcl_address[i] == ' ')
94  {
95  if (start < i) //if not zero length
96  args.push_back(gcl_address.substr(start, i - start));
97 
98  start = i + 1; //jump over space
99  }
100  }
101  if (start < i) //one token still remaining
102  args.push_back(gcl_address.substr(start, i - start));
103 
104  bool ei = true; //bools to remember if data streams should be subscribed to, gcl subscribes by default
105  bool mg = true;
106  bool dr = true;
107  string address;
108  args.push_back(""); //allow safe indexing one past the end of the tokens list
109  for (i = 0; i < args.size() - 1; i++)
110  {
111  if (args[i] == "-p1") address.append("--p1 " + args[++i] + " ");
112  else if (args[i] == "-p2") address.append("--p2 " + args[++i] + " ");
113  else if (args[i] == "-udp") address.append("--command UDP "); //TCP is default in gclib
114  else if ((args[i] == "-ei") && (args[++i] == "0")) ei = false;
115  else if ((args[i] == "-mg") && (args[++i] == "0")) mg = false;
116  else if ((args[i] == "-dr") && (args[++i] == "0")) dr = false;
117  else if (args[i] == "-t") address.append("-t " + args[++i] + " ");
118  else if (args[i] == "-s")
119  {
120  address.append("-s NONE ");
121  ei = false;
122  mg = false;
123  dr = false;
124  }
125  else if (args[i] == "-d") ++i; //Debug not yet supported
126  else if (args[i] == "-l") ++i; //Long-timeout not used
127  else if (args[i].find("COM") != string::npos)
128  {
129  address.append(args[i] + " --baud " + args[i + 1] + " "); //COM1 --baud 115200
130  i++;// jump over baud rate on next pass
131  }
132  else address.append(args[i] + " "); //keep unrecognized tokens, e.g. 192.168.0.123
133  }
134 
135  if (ei) address.append("-s EI ");
136  if (mg) address.append("-s MG ");
137  if (dr) address.append("-s DR ");
138 
139  address.append("-d "); //add direct-connect switch
140 
141  return address;
142 }
143 
144 string Galil::libraryVersion()
145 {
146  char buf[G_SMALL_BUFFER]; //function is static, so can't access GalilPrivate members
147  ec(GVersion(buf, sizeof(buf)));
148  return "Galil2.dll wrapper, gclib " + string(buf);
149 }
150 
151 vector<string> Galil::addresses()
152 {
153  vector<string> addresses; //this is the return collection
154  char buf[1024];
155  ec(GAddresses(buf, sizeof(buf)));
156  //buf now holds the list, but the gcl only holds the first cell
157 
158  short commas = 0; //counter for comma delimiters
159  string address; //temp buffer for holding chars
160  size_t len = strlen(buf); //don't call strlen every iteration
161  for (size_t i = 0; i < len; i++)
162  {
163  if (buf[i] == '\n') //end of line
164  {
165  addresses.push_back(address);
166  address.clear();
167  commas = 0; //start counting commas from zero
168  continue;
169  }
170 
171  if (commas) //already saw first comma, keep looking for end of line
172  continue;
173 
174  if (buf[i] == ',')
175  {
176  commas++; //count it
177  continue;
178  }
179 
180  address.push_back(buf[i]); //keep the char
181  }//for
182 
183  return addresses;
184 }
185 
186 Galil::Galil(std::string address)
187 {
188  GCon g;
189  timeout_ms = 500; //default value for gcl
190  ec(GOpen(AddressConvert(address).c_str(), &g));
191  d = new GalilPrivate(this, g);
192  d->InitializeDataRecord();
193 }
194 
195 Galil::~Galil()
196 {
197  GClose(d->g); //close the connection in gclib
198  delete d; //free memory
199 }
200 
201 string Galil::connection()
202 {
203  ec(GInfo(d->g, d->tbuf, sizeof(d->tbuf)));
204  return string(d->tbuf);
205 }
206 
207 string Galil::command(const std::string& command, const std::string& terminator, const std::string& ack, bool trim)
208 {
209  /*
210  * Note: This wrapper ignores terminator and ack. GCommand does not require them to operate.
211  * If terminator and/or ack are desired, this function can be implemented with GRead and GWrite.
212  * Please contact softwaresupport@galil.com with questions/concerns.
213  */
214  ec(GTimeout(d->g, (short)timeout_ms)); //obey timeout_ms setting
215  GSize bytes_read;
216  char* response;
217  if (trim)
218  ec(GCmdT(d->g, command.c_str(), d->tbuf, sizeof(d->tbuf), &response));
219  else
220  {
221  ec(GCommand(d->g, command.c_str(), d->tbuf, sizeof(d->tbuf), &bytes_read));
222  response = d->tbuf;
223  }
224  ec(GTimeout(d->g, -1)); //replace timeout
225 
226  return string(response);
227 }
228 
229 double Galil::commandValue(const std::string& command)
230 {
231  double value;
232  ec(GTimeout(d->g, (short)timeout_ms));
233  ec(GCmdD(d->g, command.c_str(), &value));
234  ec(GTimeout(d->g, -1));
235  return value;
236 }
237 
238 string Galil::message(int timeout_ms)
239 {
240  /*
241  * From GCL documentation, http://www.galil.com/sw/pub/all/doc/galiltools/html/library.html#message
242  * "If a zero timeout is specified, no errors will be thrown; message() will simply return the waiting queue (even if it is empty, "").
243  * A -1 timeout will cause message() to block until a message is received."
244  */
245  GReturn rc = G_NO_ERROR;
246  short t = 5000; //nominal timeout, to be used if -1 is specified
247  if (timeout_ms >= 0)
248  t = (short) timeout_ms;
249 
250  ec(GTimeout(d->g, t));
251 
252  do
253  {
254  rc = GMessage(d->g, d->tbuf, sizeof(d->tbuf));
255  } while(timeout_ms == -1 && rc == G_TIMEOUT);
256 
257  ec(GTimeout(d->g, -1));
258 
260  return "";
261 
262  ec(rc); //check the other possible return codes
263  return string(d->tbuf);
264 
265 }
266 
267 int Galil::interrupt(int timeout_ms)
268 {
269  ec(GTimeout(d->g, (short)timeout_ms));
270  GStatus status;
271  ec(GInterrupt(d->g, &status));
272  ec(GTimeout(d->g, -1));
273  return (int)status;
274 }
275 
276 
277 string Galil::programUpload()
278 {
279  ec(GTimeout(d->g, (short)timeout_ms));
280  ec(GProgramUpload(d->g, d->tbuf, sizeof(d->tbuf)));
281  ec(GTimeout(d->g, -1));
282  return string(d->tbuf);
283 }
284 
285 void Galil::programDownload(const std::string& program)
286 {
287  ec(GTimeout(d->g, (short)timeout_ms));
288  ec(GProgramDownload(d->g, program.c_str(), 0)); //no special preprocessor directives
289  ec(GTimeout(d->g, -1));
290 }
291 
292 void Galil::programUploadFile(const std::string& file)
293 {
294  ec(GTimeout(d->g, (short)timeout_ms));
295  ec(GProgramUploadFile(d->g, file.c_str()));
296  ec(GTimeout(d->g, -1));
297 }
298 
299 void Galil::programDownloadFile(const std::string& file)
300 {
301  ec(GTimeout(d->g, (short)timeout_ms));
302  ec(GProgramDownloadFile(d->g, file.c_str(), 0)); //no special preprocessor directives
303  ec(GTimeout(d->g, -1));
304 }
305 
306 vector<double> Galil::arrayUpload(const std::string& name)
307 {
308  ec(GTimeout(d->g, (short)timeout_ms));
309  ec(GArrayUpload(d->g, name.c_str(), G_BOUNDS, G_BOUNDS, G_CR, d->tbuf, sizeof(d->tbuf)));
310  ec(GTimeout(d->g, -1));
311 
312  vector<double> vals;
313  int len = strlen(d->tbuf); //gclib null terminates array buf
314  char* start = d->tbuf; //start hold pointer to begining of string to atof
315  for (int i = 0; i < len; i++)
316  {
317  if (d->tbuf[i] == '\r')
318  {
319  vals.push_back(atof(start));
320  start = d->tbuf + i;
321  }
322  }
323  vals.push_back(atof(start)); //last number still left in tbuf
324  return vals;
325 }
326 
327 void Galil::arrayDownload(const std::vector<double>& array, const std::string& name)
328 {
329  //GArrayDownload requires a cstring containing the data
330  string array_str;
331  for (size_t i = 0; i < array.size(); i++)
332  {
333  sprintf(d->tbuf, "%0.4f\r", array[i]);
334  array_str.append(d->tbuf);
335  }
336  ec(GTimeout(d->g, (short)timeout_ms));
337 
338  //Galil::arrayDownload auto-dimensions the array table
339  string command = "DA " + name + "[]";
340  ec(GCmd(d->g, command.c_str())); //Deallocate array
341  command = "DM " + name + "[" + to_string(array.size()) + "]";
342  ec(GCmd(d->g, command.c_str())); //Allocate array with correct dimension
343 
344  ec(GArrayDownload(d->g, name.c_str(), G_BOUNDS, G_BOUNDS, array_str.c_str()));
345  ec(GTimeout(d->g, -1));
346 }
347 
348 void Galil::arrayUploadFile(const std::string& file, const std::string& names)
349 {
350  ec(GTimeout(d->g, (short)timeout_ms));
351  ec(GArrayUploadFile(d->g, file.c_str(), names.c_str()));
352  ec(GTimeout(d->g, -1));
353 }
354 
355 void Galil::arrayDownloadFile(const std::string& file)
356 {
357  ec(GTimeout(d->g, (short)timeout_ms));
358  ec(GArrayDownloadFile(d->g, file.c_str()));
359  ec(GTimeout(d->g, -1));
360 }
361 
362 void Galil::firmwareDownloadFile(const std::string& file)
363 {
364  ec(GTimeout(d->g, (short)timeout_ms));
365  ec(GFirmwareDownload(d->g, file.c_str()));
366  ec(GTimeout(d->g, -1));
367 }
368 
369 int Galil::write(const std::string& bytes)
370 {
371  ec(GTimeout(d->g, (short)timeout_ms));
372  ec(GWrite(d->g, bytes.data(), bytes.length()));
373  ec(GTimeout(d->g, -1));
374  return bytes.length();
375 }
376 
377 string Galil::read()
378 {
379  ec(GTimeout(d->g, (short)timeout_ms));
380  GSize bytes_read;
381  ec(GRead(d->g, d->tbuf, sizeof(d->tbuf), &bytes_read));
382  ec(GTimeout(d->g, -1));
383  return string(d->tbuf, bytes_read); //data is not null-terminatated, so construct string "from buffer"
384 }
385 
string AddressConvert(const string &gcl_address)
Takes a GCL address string and returns the equivalent gclib address string.
Definition: gcl_galil.cpp:80
GCLIB_DLL_EXPORTED GReturn GCALL GCmdT(GCon g, GCStringIn command, GCStringOut trimmed_response, GSize response_len, GCStringOut *front)
Wrapper around GCommand that trims the response.
Definition: gclibo.c:243
GCLIB_DLL_EXPORTED GReturn GCALL GArrayDownloadFile(GCon g, GCStringIn file_path)
Array download from file.
Definition: arrays.c:380
GCLIB_DLL_EXPORTED GReturn GCALL GFirmwareDownload(GCon g, GCStringIn filepath)
Upgrade firmware.
GCLIB_DLL_EXPORTED GReturn GCALL GArrayUploadFile(GCon g, GCStringIn file_path, GCStringIn names)
Array upload to file.
Definition: arrays.c:408
GCLIB_DLL_EXPORTED GReturn GCALL GClose(GCon g)
Closes a connection to a Galil Controller.
GCLIB_DLL_EXPORTED GReturn GCALL GProgramDownloadFile(GCon g, GCStringIn file_path, GCStringIn preprocessor)
Program download from file.
Definition: gclibo.c:387
GCLIB_DLL_EXPORTED GReturn GCALL GTimeout(GCon g, short timeout_ms)
Uses GUtility() and G_UTIL_TIMEOUT_OVERRIDE to set the library timeout.
Definition: gclibo.c:65
GCLIB_DLL_EXPORTED GReturn GCALL GVersion(GCStringOut ver, GSize ver_len)
Uses GUtility(), G_UTIL_VERSION and G_UTIL_GCAPS_VERSION to provide the library and gcaps version num...
Definition: gclibo.c:29
GCLIB_DLL_EXPORTED GReturn GCALL GCommand(GCon g, GCStringIn command, GBufOut buffer, GSize buffer_len, GSize *bytes_returned)
Performs a command-and-response transaction on the connection.
GCLIB_DLL_EXPORTED GReturn GCALL GInterrupt(GCon g, GStatus *status_byte)
Provides access to PCI and UDP interrupts from the controller.
GCLIB_DLL_EXPORTED GReturn GCALL GWrite(GCon g, GBufIn buffer, GSize buffer_len)
Performs a write on the connection.
GCLIB_DLL_EXPORTED GReturn GCALL GArrayDownload(GCon g, const GCStringIn array_name, GOption first, GOption last, GCStringIn buffer)
Downloads array data to a pre-dimensioned array in the controller's array table.
GCLIB_DLL_EXPORTED GReturn GCALL GProgramUpload(GCon g, GBufOut buffer, GSize buffer_len)
Uploads a program from the controller's program buffer.
GCLIB_DLL_EXPORTED void GCALL GError(GReturn rc, GCStringOut error, GSize error_len)
Provides a human-readable description string for return codes.
Definition: gclibo.c:459
GCLIB_DLL_EXPORTED GReturn GCALL GProgramUploadFile(GCon g, GCStringIn file_path)
Program upload to file.
Definition: gclibo.c:430
GCLIB_DLL_EXPORTED GReturn GCALL GMessage(GCon g, GCStringOut buffer, GSize buffer_len)
Provides access to unsolicited messages from the controller.
GCLIB_DLL_EXPORTED GReturn GCALL GProgramDownload(GCon g, GCStringIn program, GCStringIn preprocessor)
Downloads a program to the controller's program buffer.
GCLIB_DLL_EXPORTED GReturn GCALL GInfo(GCon g, GCStringOut info, GSize info_len)
Uses GUtility() and G_UTIL_INFO to provide a useful connection string.
Definition: gclibo.c:49
GCLIB_DLL_EXPORTED GReturn GCALL GCmdD(GCon g, GCStringIn command, double *value)
Wrapper around GCommand that provides the return value of a command parsed into a double.
Definition: gclibo.c:289
GCLIB_DLL_EXPORTED GReturn GCALL GRead(GCon g, GBufOut buffer, GSize buffer_len, GSize *bytes_read)
Performs a read on the connection.
GCLIB_DLL_EXPORTED GReturn GCALL GCmd(GCon g, GCStringIn command)
Wrapper around GCommand for use when the return value is not desired.
Definition: gclibo.c:237
GCLIB_DLL_EXPORTED GReturn GCALL GAddresses(GCStringOut addresses, GSize addresses_len)
Uses GUtility(), G_UTIL_GCAPS_ADDRESSES or G_UTIL_ADDRESSES to provide a listing of all available con...
Definition: gclibo.c:54
GCLIB_DLL_EXPORTED GReturn GCALL GOpen(GCStringIn address, GCon *g)
Open a connection to a Galil Controller.
GCLIB_DLL_EXPORTED GReturn GCALL GArrayUpload(GCon g, const GCStringIn array_name, GOption first, GOption last, GOption delim, GBufOut buffer, GSize buffer_len)
Uploads array data from the controller's array table.
#define G_BAD_RESPONSE_QUESTION_MARK
Operation received a ?, indicating controller has a TC error.
Definition: gclib_errors.h:73
#define G_DATA_RECORD_ERROR
Data record error, e.g. DR attempted on serial connection.
Definition: gclib_errors.h:52
#define G_COMMAND_CALLED_WITH_ILLEGAL_COMMAND
GCommand() was called with an illegal command, e.g. ED, DL or QD.
Definition: gclib_errors.h:49
#define G_CR
For GArrayUpload(), use this value in the delim field to delimit with carriage returns.
Definition: gclib.h:53
int GReturn
Every function returns a value of type GReturn. See gclib_errors.h for possible values.
Definition: gclib.h:93
#define G_SMALL_BUFFER
Most reads from Galil are small. This value will easily hold most, e.g. TH, TZ, etc.
Definition: gclib.h:89
unsigned char GStatus
Interrupt status byte.
Definition: gclib.h:101
#define G_OPEN_ERROR
Device could not be opened. E.G. Serial port or PCI device already open.
Definition: gclib_errors.h:34
#define G_NO_ERROR
Return value if function succeeded.
Definition: gclib_errors.h:13
#define G_BOUNDS
For functions that take range options, e.g. GArrayUpload(), use this value for full range.
Definition: gclib.h:52
unsigned int GSize
Size of buffers, etc.
Definition: gclib.h:95
#define G_FIRMWARE_LOAD_NOT_SUPPORTED
Firmware is not supported on this bus, e.g. Ethernet for the DMC-21x3 series.
Definition: gclib_errors.h:58
void * GCon
Connection handle. Unique for each connection in process. Assigned a non-zero value in GOpen().
Definition: gclib.h:94
#define G_UNSUPPORTED_FUNCTION
Function cannot be called on this bus. E.G. GInterrupt() on serial.
Definition: gclib_errors.h:55
#define G_BAD_FILE
Bad file path, bad file contents, or bad write.
Definition: gclib_errors.h:85
#define G_GCLIB_NON_BLOCKING_READ_EMPTY
GMessage, GInterrupt, and GRecord can be called with a zero timeout. If there wasn't data waiting in ...
Definition: gclib_errors.h:25
#define G_UNABLE_TO_COMPRESS_PROGRAM_TO_FIT
Program preprocessor could not compress the program within the user's constraints.
Definition: gclib_errors.h:70
#define G_TIMEOUT
Operation timed out. Timeout is set by the –timeout option in GOpen() and can be overriden by GSettin...
Definition: gclib_errors.h:31
#define G_ILLEGAL_DATA_IN_PROGRAM
Data to download not valid, e.g. \ in data.
Definition: gclib_errors.h:67