gclib  396
Communications API for Galil controllers and PLCs
 All Data Structures Files Functions Variables Typedefs Macros Pages
gclibo.c
Go to the documentation of this file.
1 
7 #include "gclibo.h"
8 #define _CRT_SECURE_NO_WARNINGS //use traditional C calls like strncpy()
9 #include <stdlib.h> //atoi, atof
10 #include <string.h> //strcpy
11 #include <stdio.h> //fopen
12 #include <math.h> //log()
13 
14 
15 
16 void GCALL GSleep(unsigned int timeout_ms)
17 {
18  GUtility(0, G_UTIL_SLEEP, &timeout_ms, 0);
19 }
20 
22 {
23  int str_len;
24  GReturn rc;
25  if ((rc = GUtility(0, G_UTIL_VERSION, ver, &ver_len)) != G_NO_ERROR)
26  return rc;
27 
28 #ifdef G_USE_GCAPS
29  str_len = strlen(ver) + 1;
30  ver_len -= str_len;
31  if (ver_len > 0
32  && GUtility(0, G_UTIL_GCAPS_VERSION, ver + str_len, &ver_len) == G_NO_ERROR)
33  {
34  ver[str_len - 1] = ' '; //add a delimiter
35  }
36 #endif
37 
38  return rc;
39 }
40 
42 {
43  return GUtility(g, G_UTIL_INFO, info, &info_len);
44 }
45 
46 GReturn GCALL GAddresses(GCStringOut addresses, GSize addresses_len)
47 {
48 #ifdef G_USE_GCAPS
49  GReturn rc;
50  if (G_NO_ERROR == (rc = GUtility(0, G_UTIL_GCAPS_ADDRESSES, addresses, &addresses_len)))
51  return rc;
52 #endif
53 
54  return GUtility(0, G_UTIL_ADDRESSES, addresses, &addresses_len);
55 }
56 
57 GReturn GCALL GTimeout(GCon g, short timeout_ms)
58 {
59  return GUtility(g, G_UTIL_TIMEOUT_OVERRIDE, &timeout_ms, 0);
60 }
61 
62 GReturn GCALL GAssign(char* ip, char* mac)
63 {
64  /*
65  * On Linux and Apple, the IP address is pinged prior to assigning.
66  * On Windows, pinging first can make the arp table stale, and the
67  * IP address unreachable for several seconds. We skip ping so that
68  * we can immediately connect.
69  */
70 
71  GReturn rc;
72  int reply = 0; //ping reply is nonzero
73 
74 #ifdef G_USE_GCAPS
75 
76 #if defined(__linux__) || defined(__APPLE__)
77  GUtility(0, G_UTIL_GCAPS_PING, ip, &reply); //ping to see if IP address is already taken
78  if (reply)
80 #endif
81 
82  if (G_NO_ERROR == (rc = GUtility(0, G_UTIL_GCAPS_ASSIGN, ip, mac)))
83  return rc;
84 #endif
85 
86 #if defined(__linux__) || defined(__APPLE__)
87  GUtility(0, G_UTIL_PING, ip, &reply); //ping to see if IP address is already taken
88  if (reply)
90 #endif
91 
92  return GUtility(0, G_UTIL_ASSIGN, ip, mac);
93 }
94 
95 GReturn GCALL GIpRequests(GCStringOut requests, GSize requests_len)
96 {
97 #ifdef G_USE_GCAPS
98  GReturn rc;
99  if (G_NO_ERROR == (rc = GUtility(0, G_UTIL_GCAPS_IPREQUEST, requests, &requests_len)))
100  return rc;
101 #endif
102 
103  return GUtility(0, G_UTIL_IPREQUEST, requests, &requests_len);
104 }
105 
107 {
108  char buf[G_SMALL_BUFFER]; //response usually brief, e.g. :
109  return GCommand(g, command, buf, G_SMALL_BUFFER, 0);
110 }
111 
112 GReturn GCALL GCmdT(GCon g, GCStringIn command, GCStringOut trimmed_response, GSize response_len, GCStringOut* front)
113 {
114  GSize read;
115  GReturn rc;
116  int i;
117  char c;
118  if ((rc = GCommand(g, command, trimmed_response, response_len, &read)) != G_NO_ERROR)
119  return rc;
120  //if here, the data is already null-terminated, just trim.
121  for (i = read - 1; i >= 0; i--) //read does NOT include null terminator.
122  {
123  c = trimmed_response[i];
124  if ((c == ':') || (c == '\n') || (c == '\r'))
125  trimmed_response[i] = 0; //trim it
126  else
127  break; //we hit non-trimmable data, bail out.
128  }
129 
130  if (front) //null to skip "trim" on front.
131  {
132  *front = trimmed_response;
133  i = 0;
134  do
135  {
136  c = trimmed_response[i++];
137  if (c == ' ')
138  (*front)++;
139  else
140  break;
141  } while (1); //exit will be any non-space, including null terminator
142  }
143 
144  return G_NO_ERROR;
145 }
146 
147 GReturn GCALL GCmdI(GCon g, GCStringIn command, int* value)
148 {
149  char buf[G_SMALL_BUFFER]; //response should be ~19 chars
150  GSize read;
151  GReturn rc;
152  if ((rc = GCommand(g, command, buf, G_SMALL_BUFFER, &read)) != G_NO_ERROR)
153  return rc;
154  *value = atoi(buf);
155  return G_NO_ERROR;
156 }
157 
158 GReturn GCALL GCmdD(GCon g, GCStringIn command, double* value)
159 {
160  char buf[G_SMALL_BUFFER]; //response should be ~19 chars
161  GSize read;
162  GReturn rc;
163  if ((rc = GCommand(g, command, buf, G_SMALL_BUFFER, &read)) != G_NO_ERROR)
164  return rc;
165  *value = atof(buf);
166  return G_NO_ERROR;
167 }
168 
170 {
171 
172  char buf[G_SMALL_BUFFER]; //response should be ~19 chars.
173  char cmd[] = "MG_BGm"; //command for polling the axis' motion status, m is a place holder replaced below.
174  GSize read;
175  GReturn rc;
176  GSize i = 0; //C, not C++
177  GSize len = strlen(axes);
178 
179  for (i = 0; i < len; i++) //iterate through all chars in axes
180  {
181  cmd[5] = axes[i]; //set the axis
182  poll:
183  if ((rc = GCommand(g, cmd, buf, G_SMALL_BUFFER, &read)) != G_NO_ERROR)
184  return rc;
185  if (atoi(buf))
186  {
188  goto poll;
189  }
190  }// for
191 
192  return G_NO_ERROR;
193 }
194 
195 GReturn GCALL GRecordRate(GCon g, double period_ms)
196 {
197  char buf[G_SMALL_BUFFER];
198  double dt;
199  double period_arg;
200 
201  if (period_ms == 0) //turn off
202  return GCmd(g, "DR 0");
203 
204  if (GCmdD(g, "TM?", &dt) == G_NO_ERROR)
205  {
206  dt /= 1024.0; //ms per controller sample
207  if (!dt) dt = 1; //don't want to divide by zero below
208  }
209  else
210  {
211  dt = 0.9765625; //RIO doesn't have TM
212  }
213 
214  period_arg = period_ms / dt; //data record specified in samples between records
215 
216  if (GCmdT(g, "\x12\x16", buf, sizeof(buf), 0) == G_NO_ERROR) //Revision string, ^R^V
217  {
218  if (strstr(buf, "DMC18")) //PCI controller
219  period_arg = log(period_arg) / log(2.0); //PCI DR arg is 2^n.
220  else if ((strstr(buf, "DMC40") != NULL) //4000
221  || (strstr(buf, "DMC500") != NULL) //50000
222  || (strstr(buf, "RIO") != NULL)) // RIO
223  {
224  if (period_arg < 2) period_arg = 2; //lowest non-zero DR
225  }
226  else if ((strstr(buf, "DMC41") != NULL) || (strstr(buf, "DMC21") != NULL)) //4103, 2103
227  {
228  if (period_arg < 8) period_arg = 8; //lowest non-zero DR
229  }
230  else if ((strstr(buf, "DMC3") != NULL)) //30010, 31010
231  {
232  if (period_arg < 4) period_arg = 4; //lowest non-zero DR
233  }
234  }
235 
236  sprintf(buf, "DR %d", (int)period_arg);
237  return GCmd(g, buf);
238 }
239 
241 {
242  FILE *file;
243  long file_size;
244  char* program_buffer;
245  GReturn rc = G_NO_ERROR;
246 
247  if (!(file = fopen(file_path, "rb"))) //open file for reading, binary mode
248  return G_BAD_FILE;
249 
250  fseek(file, 0, SEEK_END); //find end of file
251  file_size = ftell(file); //add one to null terminate below
252  rewind(file);
253 
254  if (file_size) //don't malloc 0.
255  {
256 
257  if (!(program_buffer = malloc(file_size + 1))) //allocate memory for the data, +1 for null termination below
258  {
259  fclose(file);
260  return G_BAD_FULL_MEMORY;
261  }
262 
263  if (file_size != fread(program_buffer, 1, file_size, file))
264  {
265  fclose(file);
266  free(program_buffer); //free memory
267  return G_BAD_FILE;
268  }
269  program_buffer[file_size] = 0; //null terminate, malloc was one byte larger for this
270  }
271  else
272  {
273  program_buffer = ""; //nullstring
274  }
275 
276  fclose(file); //done with file, close it
277 
278  rc = GProgramDownload(g, program_buffer, preprocessor); //call the gclib downloader
279  if (file_size) free(program_buffer); //free memory
280  return rc;
281 }
282 
284 {
285  FILE *file;
286  GReturn rc = G_NO_ERROR;
287  char* program_buffer;
288  long file_size;
289 
290  if (!(file = fopen(file_path, "wb"))) //open file for writing, binary mode
291  return G_BAD_FILE;
292 
293  if (!(program_buffer = malloc(MAXPROG))) //allocate memory for the data
294  {
295  fclose(file);
296  return G_BAD_FULL_MEMORY;
297  }
298 
299  if ((rc = GProgramUpload(g, program_buffer, MAXPROG)) == G_NO_ERROR)
300  {
301  file_size = strlen(program_buffer);
302  if (file_size != fwrite(program_buffer, 1, file_size, file))
303  rc = G_BAD_FILE;
304  }
305 
306  fclose(file);
307  free(program_buffer);
308  return rc;
309 }
310 
311 
312 void GCALL GError(GReturn rc, GCStringOut error, GSize error_len)
313 {
314  char* error_message;
315 
316  switch (rc)
317  {
318  case G_NO_ERROR:
319  error_message = G_NO_ERROR_S;
320  break;
321 
322  case G_GCLIB_ERROR:
323  error_message = G_GCLIB_ERROR_S;
324  break;
325 
327  error_message = G_GCLIB_UTILITY_ERROR_S;
328  break;
329 
331  error_message = G_GCLIB_UTILITY_IP_TAKEN_S;
332  break;
333 
335  error_message = G_GCLIB_NON_BLOCKING_READ_EMPTY_S;
336  break;
337 
338  case G_TIMEOUT:
339  error_message = G_TIMEOUT_S;
340  break;
341 
342  case G_OPEN_ERROR:
343  error_message = G_OPEN_ERROR_S;
344  break;
345 
346  case G_READ_ERROR:
347  error_message = G_READ_ERROR_S;
348  break;
349 
350  case G_WRITE_ERROR:
351  error_message = G_WRITE_ERROR_S;
352  break;
353 
355  error_message = G_COMMAND_CALLED_WITH_ILLEGAL_COMMAND_S;
356  break;
357 
358  case G_DATA_RECORD_ERROR:
359  error_message = G_DATA_RECORD_ERROR_S;
360  break;
361 
363  error_message = G_UNSUPPORTED_FUNCTION_S;
364  break;
365 
366  case G_BAD_ADDRESS:
367  error_message = G_BAD_ADDRESS_S;
368  break;
369 
371  error_message = G_FIRMWARE_LOAD_NOT_SUPPORTED_S;
372  break;
373 
375  error_message = G_ARRAY_NOT_DIMENSIONED_S;
376  break;
377 
379  error_message = G_ILLEGAL_DATA_IN_PROGRAM_S;
380  break;
381 
383  error_message = G_UNABLE_TO_COMPRESS_PROGRAM_TO_FIT_S;
384  break;
385 
387  error_message = G_INVALID_PREPROCESSOR_OPTIONS_S;
388  break;
389 
391  error_message = G_BAD_RESPONSE_QUESTION_MARK_S;
392  break;
393 
394  case G_BAD_VALUE_RANGE:
395  error_message = G_BAD_VALUE_RANGE_S;
396  break;
397 
398  case G_BAD_FULL_MEMORY:
399  error_message = G_BAD_FULL_MEMORY_S;
400  break;
401 
402  case G_BAD_LOST_DATA:
403  error_message = G_BAD_LOST_DATA_S;
404  break;
405 
406  case G_BAD_FILE:
407  error_message = G_BAD_FILE_S;
408  break;
409 
410  case G_GCAPS_OPEN_ERROR:
411  error_message = G_GCAPS_OPEN_ERROR_S;
412  break;
413 
415  error_message = G_GCAPS_SUBSCRIPTION_ERROR_S;
416  break;
417 
418  default:
419  error_message = "internal error";
420  break;
421  }
422 
423  strncpy(error, error_message, error_len);
424  error[error_len - 1] = 0; //ensure null termination
425 }
void GCALL GSleep(unsigned int timeout_ms)
Uses GUtility() and G_UTIL_SLEEP to provide a blocking sleep call which can be useful for timing-base...
Definition: gclibo.c:16
#define G_SMALL_BUFFER
Most reads/writes to Galil are small. This value will easily hold most, e.g. TH, TZ, etc.
Definition: gclib.h:66
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:41
unsigned int GSize
Size of buffers, etc.
Definition: gclib.h:71
#define G_UTIL_IPREQUEST
GUtility(), get a list of hardware requesting IPs.
Definition: gclib.h:50
#define G_UTIL_GCAPS_IPREQUEST
GUtility(), get a list of hardware requesting IPs from the gcaps server.
Definition: gclib.h:60
#define G_UTIL_PING
GUtility(), uses ICMP ping to determine if an IP address is reachable and assigned.
Definition: gclib.h:53
#define G_UNABLE_TO_COMPRESS_PROGRAM_TO_FIT
Program preprocessor could not compress the program within the user's constraints.
Definition: gclib_errors.h:57
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:112
#define MAXPROG
Maximum size for a program.
Definition: gclibo.h:34
#define G_COMMAND_CALLED_WITH_ILLEGAL_COMMAND
GCommand() was called with an illegal command, e.g. ED, DL or QD.
Definition: gclib_errors.h:39
#define G_DATA_RECORD_ERROR
Data record error, e.g. DR attempted on serial connection.
Definition: gclib_errors.h:42
#define G_OPEN_ERROR
Device could not be opened. E.G. Serial port or PCI device already open.
Definition: gclib_errors.h:27
#define G_ILLEGAL_DATA_IN_PROGRAM
Data to download not valid, e.g. \ in data.
Definition: gclib_errors.h:54
GReturn GCALL GProgramUploadFile(GCon g, GCStringIn file_path)
Program upload to file.
Definition: gclibo.c:283
#define G_BAD_RESPONSE_QUESTION_MARK
Operation received a ?, indicating controller has a TC error.
Definition: gclib_errors.h:60
GCLIB_DLL_EXPORTED GReturn GCALL GUtility(GCon g, GOption request, GMemory memory1, GMemory memory2)
Provides read/write access to driver settings and convenience features based on the request variable...
#define G_ARRAY_NOT_DIMENSIONED
Array operation was called on an array that was not in the controller's array table, see LA command.
Definition: gclib_errors.h:51
#define G_TIMEOUT
Operation timed out. Timeout is set by the –timeout option in GOpen() and can be overriden by GSetti...
Definition: gclib_errors.h:24
#define G_GCAPS_SUBSCRIPTION_ERROR
GMessage(), GRecord(), GInterrupt() called on a connection without –subscribe switch.
Definition: gclib_errors.h:81
#define POLLINGINTERVAL
Interval, in miliseconds, for polling commands, e.g. GMotionComplete().
Definition: gclibo.h:36
GReturn GCALL GCmdI(GCon g, GCStringIn command, int *value)
Wrapper around GCommand that provides the return value of a command parsed into an int...
Definition: gclibo.c:147
#define G_GCLIB_UTILITY_ERROR
An invalid request value was specified to GUtility.
Definition: gclib_errors.h:15
GReturn GCALL GMotionComplete(GCon g, GCStringIn axes)
Blocking call that returns once all axes specified have completed their motion.
Definition: gclibo.c:169
#define G_UTIL_SLEEP
GUtility(), specify an interval to sleep.
Definition: gclib.h:48
#define G_GCAPS_OPEN_ERROR
gcaps connection couldn't open. Server is not running or is not reachable.
Definition: gclib_errors.h:78
#define G_UNSUPPORTED_FUNCTION
Function cannot be called on this bus. E.G. GInterrupt() on serial.
Definition: gclib_errors.h:45
GReturn GCALL GCmd(GCon g, GCStringIn command)
Wrapper around GCommand for use when the return value is not desired.
Definition: gclibo.c:106
#define G_GCLIB_ERROR
General library error. Indicates internal API caught an unexpected error. Contact Galil support if th...
Definition: gclib_errors.h:12
#define G_UTIL_ADDRESSES
GUtility(), get a list of available connections.
Definition: gclib.h:49
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:21
#define G_UTIL_INFO
GUtility(), get a connection info string.
Definition: gclib.h:47
void * GCon
Connection handle. Unique for each connection in process. Assigned a non-zero value in GOpen()...
Definition: gclib.h:70
#define G_UTIL_TIMEOUT_OVERRIDE
GUtility(), read/write access to timeout override.
Definition: gclib.h:44
#define G_UTIL_GCAPS_VERSION
GUtility(), get the version of the gcaps server.
Definition: gclib.h:57
void GCALL GError(GReturn rc, GCStringOut error, GSize error_len)
Provides a human-readable description string for return codes.
Definition: gclibo.c:312
GCLIB_DLL_EXPORTED GReturn GCALL GProgramDownload(GCon g, GCStringIn program, GCStringIn preprocessor)
Downloads a program to the controller's program buffer.
#define G_READ_ERROR
Device read failed. E.G. Socket was closed by remote host. See G_UTIL_GCAPS_KEEPALIVE.
Definition: gclib_errors.h:30
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 GProgramUpload(GCon g, GBufOut buffer, GSize buffer_len)
Uploads a program from the controller's program buffer.
GReturn GCALL GTimeout(GCon g, short timeout_ms)
Uses GUtility() and G_UTIL_TIMEOUT_OVERRIDE to set the library timeout.
Definition: gclibo.c:57
int GReturn
Every function returns a value of type GReturn. See gclib_errors.h for possible values.
Definition: gclib.h:69
#define G_GCLIB_UTILITY_IP_TAKEN
The IP cannot be assigned because ping returned a reply.
Definition: gclib_errors.h:18
GReturn GCALL GIpRequests(GCStringOut requests, GSize requests_len)
Uses GUtility(), G_UTIL_GCAPS_IPREQUEST or G_UTIL_IPREQUEST to provide a list of all Galil controller...
Definition: gclibo.c:95
#define G_INVALID_PREPROCESSOR_OPTIONS
GProgramDownload was called with a bad preprocessor directive.
Definition: gclib_errors.h:36
#define G_BAD_LOST_DATA
Lost data, e.g. GCommand() response buffer was too small for the controller's response.
Definition: gclib_errors.h:69
#define G_UTIL_VERSION
GUtility(), get a library version string.
Definition: gclib.h:46
#define G_BAD_FULL_MEMORY
Not enough memory for an operation, e.g. all connections allowed for a process already taken...
Definition: gclib_errors.h:66
#define G_BAD_VALUE_RANGE
Bad value or range, e.g. GCon g variable passed to function was bad.
Definition: gclib_errors.h:63
#define G_WRITE_ERROR
Device write failed. E.G. Socket was closed by remote host. See G_UTIL_GCAPS_KEEPALIVE.
Definition: gclib_errors.h:33
const char * GCStringIn
C-string input to the library. Implies null-termination.
Definition: gclib.h:74
#define G_UTIL_GCAPS_PING
GUtility(), uses ICMP ping to determine if an IP address is reachable and assigned. Ping sent from the gcaps server.
Definition: gclib.h:62
#define G_NO_ERROR
Return value if function succeeded.
Definition: gclib_errors.h:9
#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:21
#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:48
char * GCStringOut
C-string output from the library. Implies null-termination.
Definition: gclib.h:73
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:46
GReturn GCALL GAssign(char *ip, char *mac)
Uses GUtility(), G_UTIL_GCAPS_ASSIGN or G_UTIL_ASSIGN to assign an IP address over the Ethernet to a ...
Definition: gclibo.c:62
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:158
#define GCALL
Specify calling convention for Windows.
Definition: gclib.h:24
#define G_UTIL_GCAPS_ADDRESSES
GUtility(), get a list of available connections from the gcaps server.
Definition: gclib.h:59
#define G_BAD_ADDRESS
Bad address.
Definition: gclib_errors.h:75
GReturn GCALL GProgramDownloadFile(GCon g, GCStringIn file_path, GCStringIn preprocessor)
Program download from file.
Definition: gclibo.c:240
GReturn GCALL GRecordRate(GCon g, double period_ms)
Sets the asynchronous data record to a user-specified period via DR.
Definition: gclibo.c:195
#define G_BAD_FILE
Bad file path, bad file contents, or bad write.
Definition: gclib_errors.h:72
#define G_UTIL_ASSIGN
GUtility(), assign IP addresses via Boot-P reply.
Definition: gclib.h:51
#define G_UTIL_GCAPS_ASSIGN
GUtility(), assign IP addresses via Boot-P reply from the gcaps server.
Definition: gclib.h:61