gclib  2.0.8
Communications API for Galil controllers and PLCs
gcl_datarecord.cpp
Go to the documentation of this file.
1 
4 #include "gcl_galil.h"
5 using namespace std;
6 
7 vector<std::string> Galil::sources()
8 {
9  vector<std::string> s;
10  for (auto it = d->map.begin(); it != d->map.end(); ++it)
11  s.push_back(it->first);
12 
13  std::sort(s.begin(), s.end());
14 
15  return s;
16 }
17 
18 void Galil::recordsStart(double period_ms)
19 {
20  ec(GRecordRate(d->g, period_ms));
21 }
22 
23 vector<char> Galil::record(const std::string& method)
24 {
25  GDataRecord record;
26  ec(GRecord(d->g, &record, method == "QR" ? G_QR : G_DR));
27  vector <char> record_vector;
28  for (int i = 0; i < sizeof(GDataRecord); i++)
29  record_vector.push_back(record.byte_array[i]);
30 
31  return record_vector;
32 }
33 
34 double Galil::sourceValue(const std::vector<char>& record, const std::string& source)
35 {
36 
37  try
38  {
39  const Source& s = d->map.at(source); //use at() function so silent insert does not occur if bad source string is used.
40  int return_value = 0;
41  if (s.type[0] == 'U') //unsigned
42  switch (s.type[1])
43  {
44  case 'B': return_value = *(unsigned char*)(&record[0] + s.byte); break;
45  case 'W': return_value = *(unsigned short*)(&record[0] + s.byte); break;
46  case 'L': return_value = *(unsigned int*)(&record[0] + s.byte); break;
47  }
48  else //s.type[0] == 'S' //signed
49  switch (s.type[1])
50  {
51  case 'B': return_value = *(char*)(&record[0] + s.byte); break;
52  case 'W': return_value = *(short*)(&record[0] + s.byte); break;
53  case 'L': return_value = *(int*)(&record[0] + s.byte); break;
54  }
55 
56  if (s.bit >= 0) //this is a bit field
57  {
58  bool bTRUE = s.scale > 0; //invert logic if scale is <= 0
59  return return_value & (1 << s.bit) ? bTRUE : !bTRUE; //check the bit
60  }
61  else
62  return (return_value / s.scale) + s.offset;
63 
64  }
65  catch (const std::out_of_range& e) //bad source
66  {
67  (void)e; //unused
68  return 0.0;
69  }
70 
71 }
72 
73 string Galil::source(const std::string& field, const std::string& source)
74 {
75  try
76  {
77  const Source& s = d->map.at(source); //use at() function so silent insert does not occur if bad source string is used.
78  if (field == "Description")
79  return s.description;
80 
81  if (field == "Units")
82  return s.units;
83 
84  if (field == "Scale")
85  return to_string(s.scale);
86 
87  if (field == "Offset")
88  return to_string(s.offset);
89 
90  return ""; //no matches
91  }
92  catch (const std::out_of_range& e) //bad source
93  {
94  (void)e;//unused
95  return ""; //no matches
96  }
97 
98 }
99 
100 void Galil::setSource(const std::string& field, const std::string& source, const std::string& to)
101 {
102  try
103  {
104  Source& s = d->map.at(source); //use at() function so silent insert does not occur if bad source string is used.
105  if (field == "Description")
106  {
107  s.description = to;
108  return;
109  }
110 
111  if (field == "Units")
112  {
113  s.units = to;
114  return;
115  }
116 
117  if (field == "Scale")
118  {
119  s.scale = stod(to);
120  return;
121  }
122 
123  if (field == "Offset")
124  {
125  s.offset = stod(to);
126  return;
127  }
128  }
129  catch (const std::out_of_range& e) //bad source
130  {
131  (void)e;//unused
132  return;
133  }
134 }
135 
136 
137 
138 void GalilPrivate::InitializeDataRecord()
139 {
140  map.clear(); //clear the map if thre is anything in it
141 
142  //infer data record structure from QZ
143  string qz = q->command("QZ");
144  vector<int> qz_split;
145  size_t start = 0;
146  for (size_t i = 0; i < qz.length(); i++) //ad hoc split
147  {
148  if (qz[i] == ',')
149  {
150  qz_split.push_back(stoi(qz.substr(start, i - start)));
151  start = i + 1; //jump over delim
152  continue;
153  }
154 
155  if (i == qz.length() - 1) //last token
156  {
157  qz_split.push_back(stoi(qz.substr(start)));
158  break;
159  }
160  }
161 
162  if (4 != qz_split.size()) return; //parsing error or bad response
163 
164  int axes = qz_split[0];
165 
166 
167  //weed out PCI cards
168  string rv = q->command("\x12\x16"); //^R^V
169  if (rv.find("DMC18") != string::npos) //PCI-based card
170  {
171  if (rv.length() >= 7)
172  {
173  if (rv[6] == '6') return Init1806(axes);
174  if (rv[6] == '0') return Init1800(axes, false);
175  if (rv[6] == '2') return Init1800(axes, true);
176  }
177  }
178 
179  int gen_status = qz_split[1];
180  if (gen_status == 18) return Init30010(rv.find("DMC31") != string::npos); // DMC300x0 returns 1 18 16 36, search for "DMC31" in ^R^V to determine 16bit ADC
181 
182  int axis_block = qz_split[3]; //size of the axis block data in data record
183  if (axis_block == 36) return Init4000(axes); //DMC40x0/DMC41x3/DMC50000 8 52 26 36
184  if (axis_block == 28) return Init2103(axes); //DMC14x5/2xxx/ 8 24 16 28 //also Optima
185 
186  //if here, should be an RIO
187  if (axis_block != 0) return; //RIO has a 0 in the axis block data
188 
189  //Determine the RIO type
190  int io_block = qz_split[2];
191 
192  //RIO-47300 has 4 extra bytes in the I/O block
193  bool rio3 = ((io_block == 52) || (io_block == 60) || (io_block == 68)); // RIO-47300 Standard, with Exteneded I/O, with Quad/Biss/SSi
194 
195  //SER tacks 4 longs on the end of the data record (4 encoders)
196  bool rioser = ((io_block == 64) || (io_block == 68)); // 471x2,472x2 OR 47300 with SER
197 
198  //Extended I/O tacks 8 bytes on the end of the data rrecord, three bytes of each of I/O, one padding for each
199  bool rio3ex = (io_block == 60); // RIO-47300 with extended I/O. Mutually exclusive with SER
200 
201 
202  InitRio(rio3);
203 
204  if (rio3ex) InitRio3_24Ex();
205  if (rioser) InitRioSer(rio3);
206 
207 }
208 
209 string GalilPrivate::ax(string prefix, int axis, string suffix)
210 {
211  return prefix + (char)('A' + axis) + suffix;
212 }
213 
214 void GalilPrivate::input_bits(int byte, int num)
215 {
216  stringstream ss;
217 
218  for (int i = 0; i < 8; i++)
219  {
220  ss << "@IN[";
221  ss << setw(2) << setfill('0') << right << num;
222  ss << "]";
223  map[ss.str()] = Source(byte, "UB", i, "Boolean", "Digital input " + to_string(num));
224  ss.str("");
225  num++;
226  }
227 }
228 
229 void GalilPrivate::output_bits(int byte, int num)
230 {
231  stringstream ss;
232 
233  for (int i = 0; i < 8; i++)
234  {
235  ss << "@OUT[";
236  ss << setw(2) << setfill('0') << right << num;
237  ss << "]";
238  map[ss.str()] = Source(byte, "UB", i, "Boolean", "Digital output " + to_string(num));
239  ss.str("");
240  num++;
241  }
242 }
243 
244 void GalilPrivate::aq_analog(int byte, int input_num)
245 {
246  //When analog voltage decoding depends upon AQ setting.
247  string type; //for interpreting analog as signed/unsigned
248  double divisor; //for dividing ADC counts to calc volts
249  int val;
250  string command = "MG{Z10.0}_AQ" + to_string(input_num);
251  if (GCmdI(g, command.c_str(), &val) == G_NO_ERROR) //don't add analog if error on AQ
252  {
253  switch (val)
254  {
255  case 1: case -1: divisor = 32768.0 / 5; type = "SW"; break; // -5 to 5 V -32768 to 32767
256  case 3: case -3: divisor = 65536.0 / 5; type = "UW"; break; // 0 to 5 V 0 to 65535
257  case 4: case -4: divisor = 65536.0 / 10; type = "UW"; break; // 0 to 10 V 0 to 65535
258  case 2: case -2: default: //AQ 2 is the default value
259  divisor = 32768.0 / 10; type = "SW"; break; // -10 to 10 V -32768 to 32767
260  }
261  map["@AN[" + to_string(input_num + 1) + "]"] = Source(byte, type, -1, "V", "Analog input " + to_string(input_num), divisor);
262  }
263 }
264 
265 void GalilPrivate::dq_analog(int byte, int input_num)
266 {
267  //When analog voltage decoding depends upon DQ setting.
268  string type; //for interpreting analog as signed/unsigned
269  double divisor; //for dividing ADC counts to calc volts
270  int val;
271  string command = "MG{Z10.0}_DQ" + to_string(input_num);
272  if (GCmdI(g, command.c_str(), &val) == G_NO_ERROR) //don't add analog if error on AQ
273  {
274  switch (val)
275  {
276  case 3: divisor = 32768.0 / 5; type = "SW"; break; // -5 to 5 V -32768 to 32767
277  case 1: divisor = 65536.0 / 5; type = "UW"; break; // 0 to 5 V 0 to 65535
278  case 2: divisor = 65536.0 / 10; type = "UW"; break; // 0 to 10 V 0 to 65535
279  case 4: default: //DQ 4 is the default value
280  divisor = 32768.0 / 10; type = "SW"; break; // -10 to 10 V -32768 to 32767
281  }
282  map["@AO[" + to_string(input_num + 1) + "]"] = Source(byte, type, -1, "V", "Analog output " + to_string(input_num), divisor);
283  }
284 }
285 
286 void GalilPrivate::Init4000(int axes)
287 {
288  //0-3 Header is ignored in GCL
289 
290  map["TIME"] = Source(4, "UW", -1, "samples", "Sample counter");
291 
292  //Digital Inputs
293  map["_TI0"] = Source(6, "UB", -1, "", "Digital inputs 1 to 8");
294  input_bits(6, 1);
295 
296  map["_TI1"] = Source(7, "UB", -1, "", "Digital inputs 9 to 16"); //TI always included
297  if (axes > 4) //9-16 depend on axes 5-8
298  input_bits(7, 9);
299 
300  //Digital outputs
301  map["_OP0"] = Source(16, "UW", -1, "", "Digital outputs 1 to 16");
302  output_bits(16, 1);
303 
304  if (axes > 4) //9-16 depend on axes 5-8
305  output_bits(17, 9);
306 
307  //Extended I/O
308  int co = -1;
309  if (GCmdI(g, "MG_CO", &co) == G_NO_ERROR) //41x3 will ? here
310  {
311  map["_TI2"] = Source(8, "UB", -1, "", "Digital inputs 17 to 24"); //TI always included in gcl
312  map["_TI3"] = Source(9, "UB", -1, "", "Digital inputs 25 to 32");
313  map["_TI4"] = Source(10, "UB", -1, "", "Digital inputs 33 to 40");
314  map["_TI5"] = Source(11, "UB", -1, "", "Digital inputs 41 to 48");
315 
316  map["_OP1"] = Source(18, "UW", -1, "", "Digital outputs 17 to 32"); //OP always included in gcl
317  map["_OP2"] = Source(20, "UW", -1, "", "Digital outputs 33 to 48");
318 
319  if (co & 0x00000001) //bank 2 is output
320  output_bits(18, 17);
321  else //bank 2 in input
322  input_bits(8, 17);
323 
324  if (co & 0x00000002) //bank 3 is output
325  output_bits(19, 25);
326  else //bank 3 is input
327  input_bits(9, 25);
328 
329  if (co & 0x00000004) //bank 4 is output
330  output_bits(20, 33);
331  else //bank 4 is input
332  input_bits(10, 33);
333 
334  if (co & 0x00000008) //bank 5 is output
335  output_bits(21, 41);
336  else
337  input_bits(11, 41);
338  }
339 
340  //Ethernet Handle Status
341  map["_IHA2"] = Source(42, "UB", -1, "", "Handle A Ethernet status");
342  map["_IHB2"] = Source(43, "UB", -1, "", "Handle B Ethernet status");
343  map["_IHC2"] = Source(44, "UB", -1, "", "Handle C Ethernet status");
344  map["_IHD2"] = Source(45, "UB", -1, "", "Handle D Ethernet status");
345  map["_IHE2"] = Source(46, "UB", -1, "", "Handle E Ethernet status");
346  map["_IHF2"] = Source(47, "UB", -1, "", "Handle F Ethernet status");
347  map["_IHG2"] = Source(48, "UB", -1, "", "Handle G Ethernet status");
348  map["_IHH2"] = Source(49, "UB", -1, "", "Handle H Ethernet status");
349 
350  map["_TC"] = Source(50, "UB", -1, "", "Error code");
351 
352  //Thread status
353  map["NO0"] = Source(51, "UB", 0, "Boolean", "Thread 0 running");
354  map["NO1"] = Source(51, "UB", 1, "Boolean", "Thread 1 running");
355  map["NO2"] = Source(51, "UB", 2, "Boolean", "Thread 2 running");
356  map["NO3"] = Source(51, "UB", 3, "Boolean", "Thread 3 running");
357  map["NO4"] = Source(51, "UB", 4, "Boolean", "Thread 4 running");
358  map["NO5"] = Source(51, "UB", 5, "Boolean", "Thread 5 running");
359  map["NO6"] = Source(51, "UB", 6, "Boolean", "Thread 6 running");
360  map["NO7"] = Source(51, "UB", 7, "Boolean", "Thread 7 running");
361 
362  //Amplifier error status
363  map["TA00"] = Source(52, "UB", 0, "Boolean", "Axis A-D over current");
364  map["TA01"] = Source(52, "UB", 1, "Boolean", "Axis A-D over voltage");
365  map["TA02"] = Source(52, "UB", 2, "Boolean", "Axis A-D over temperature");
366  map["TA03"] = Source(52, "UB", 3, "Boolean", "Axis A-D under voltage");
367  map["TA04"] = Source(52, "UB", 4, "Boolean", "Axis E-H over current");
368  map["TA05"] = Source(52, "UB", 5, "Boolean", "Axis E-H over voltage");
369  map["TA06"] = Source(52, "UB", 6, "Boolean", "Axis E-H over temperature");
370  map["TA07"] = Source(52, "UB", 7, "Boolean", "Axis E-H under voltage");
371 
372  map["TA1A"] = Source(53, "UB", 0, "Boolean", "Axis A hall error");
373  map["TA1B"] = Source(53, "UB", 1, "Boolean", "Axis B hall error");
374  map["TA1C"] = Source(53, "UB", 2, "Boolean", "Axis C hall error");
375  map["TA1D"] = Source(53, "UB", 3, "Boolean", "Axis D hall error");
376  map["TA1E"] = Source(53, "UB", 4, "Boolean", "Axis E hall error");
377  map["TA1F"] = Source(53, "UB", 5, "Boolean", "Axis F hall error");
378  map["TA1G"] = Source(53, "UB", 6, "Boolean", "Axis G hall error");
379  map["TA1H"] = Source(53, "UB", 7, "Boolean", "Axis H hall error");
380 
381  map["TA2A"] = Source(54, "UB", 0, "Boolean", "Axis A at _TKA peak current");
382  map["TA2B"] = Source(54, "UB", 1, "Boolean", "Axis B at _TKB peak current");
383  map["TA2C"] = Source(54, "UB", 2, "Boolean", "Axis C at _TVC peak current");
384  map["TA2D"] = Source(54, "UB", 3, "Boolean", "Axis D at _TKD peak current");
385  map["TA2E"] = Source(54, "UB", 4, "Boolean", "Axis E at _TKE peak current");
386  map["TA2F"] = Source(54, "UB", 5, "Boolean", "Axis F at _TKF peak current");
387  map["TA2G"] = Source(54, "UB", 6, "Boolean", "Axis G at _TKG peak current");
388  map["TA2H"] = Source(54, "UB", 7, "Boolean", "Axis H at _TKH peak current");
389 
390  map["TA3AD"] = Source(55, "UB", 0, "Boolean", "Axis A-D ELO active");
391  map["TA3EH"] = Source(55, "UB", 1, "Boolean", "Axis E-H ELO active");
392 
393  //contour mode
394  map["CD"] = Source(56, "UL", -1, "segments", "Contour segment count");
395  map["_CM"] = Source(60, "UW", -1, "elements", "Contour buffer space");
396 
397  //S plane
398  map["_CSS"] = Source(62, "UW", -1, "segments", "Axis S segment count");
399  map["VDS"] = Source(64, "UB", 3, "Boolean", "Axis S final deceleration");
400  map["STS"] = Source(64, "UB", 4, "Boolean", "Axis S stopping");
401  map["VSS"] = Source(64, "UB", 5, "Boolean", "Axis S slewing");
402  map["_BGS"] = Source(65, "UB", 7, "Boolean", "Axis S moving");
403  map["_AVS"] = Source(66, "SL", -1, "counts", "Axis S length");
404  map["_LMS"] = Source(70, "UW", -1, "elements", "Axis S buffer speace");
405 
406  //T plane
407  map["_CST"] = Source(72, "UW", -1, "segments", "Axis T segment count");
408  map["VDT"] = Source(74, "UB", 3, "Boolean", "Axis T final deceleration");
409  map["STT"] = Source(74, "UB", 4, "Boolean", "Axis T stopping");
410  map["VST"] = Source(74, "UB", 5, "Boolean", "Axis T slewing");
411  map["_BGT"] = Source(75, "UB", 7, "Boolean", "Axis T moving");
412  map["_AVT"] = Source(76, "SL", -1, "counts", "Axis T length");
413  map["_LMT"] = Source(80, "UW", -1, "elements", "Axis T buffer speace");
414 
415  //per-axis data
416  int base = 82; //start of A axis data
417  for (int i = 0; i < axes; i++)
418  {
419  map[ax("_MO", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " motor off"));
420  map[ax("HM", i, "3")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " found index"));
421  map[ax("_AL", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " latch armed"));
422  map[ax("DC", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " began deceleration"));
423  map[ax("ST", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " began stop"));
424  map[ax("SP", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " began slew"));
425  map[ax("CM", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in contour mode"));
426  map[ax("JG", i, "-")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " negative move"));
427  ++base; //83
428  map[ax("VM", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " in VM or LI mode"));
429  map[ax("HM", i, "2")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " finding index"));
430  map[ax("HM", i, "1")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " coming off home switch"));
431  map[ax("HM", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " home command issued"));
432  map[ax("FE", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " find edge issued"));
433  map[ax("PA", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " in PA mode"));
434  map[ax("PR", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in PA or PR mode"));
435  map[ax("_BG", i, "")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " move in progress"));
436  ++base; //84
437  map[ax("MT", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " in stepper mode"));
438  map[ax("_HM", i, "")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " home switch"));
439  map[ax("_LR", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " reverse limit switch"));
440  map[ax("_LF", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " forward limit switch"));
441  //4 and 5 reserved
442  map[ax("AL", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch digital input"));
443  map[ax("_AL", i, "=0")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch occurred"));
444  ++base; //85
445  map[ax("_SC", i, "")] = Source(base, "UB", -1, "", ax("Axis ", i, " stop code"));
446  ++base; //86
447  map[ax("_RP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " reference position"));
448  base += 4; //90
449  map[ax("_TP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " encoder position"));
450  base += 4; //94
451  map[ax("_TE", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " position error"));
452  base += 4; //98
453  map[ax("_TD", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " dual encoder position"));
454  base += 4; //102
455  map[ax("_TV", i, "")] = Source(base, "SL", -1, "counts/s", ax("Axis ", i, " filtered velocity"), 64);
456  base += 4; //106
457  map[ax("_TT", i, "")] = Source(base, "SL", -1, "V", ax("Axis ", i, " torque (DAC)"), 3255);
458  base += 4; //110
459 
460  //Analog voltage decoding depends upon AQ setting.
461  aq_analog(base, i + 1);
462  base += 2; //112
463 
464  map[ax("_QH", i, "")] = Source(base, "UB", -1, "", ax("Axis ", i, " hall sensors"));
465  base += 1; //113 reserved
466  base += 1; //114
467  map[ax("_ZA", i, "")] = Source(base, "SL", -1, "", ax("Axis ", i, " user variable"));
468  base += 4; //118
469 
470  }// for, axis data
471 }
472 
473 void GalilPrivate::Init1806(int axes)
474 {
475  map["TIME"] = Source(0, "UW", -1, "samples", "Sample counter");
476 
477  //Digital inputs
478  map["_TI0"] = Source(2, "UB", -1, "", "Digital inputs 1 to 8");
479  input_bits(2, 1);
480 
481  map["_TI1"] = Source(3, "UB", -1, "", "Digital inputs 9 to 16"); //TI always included
482  if (axes > 4) //9-16 depend on axes 5-8
483  input_bits(3, 9);
484 
485 
486  //Digital outputs
487  map["_OP0"] = Source(12, "UW", -1, "", "Digital outputs 1 to 16");
488  output_bits(12, 1);
489 
490  if (axes > 4) //9-16 depend on axes 5-8
491  output_bits(13, 9);
492 
493 
494  //Extended I/O
495  int co = -1;
496  if (GCmdI(g, "MG_CO", &co) == G_NO_ERROR)
497  {
498  map["_TI2"] = Source(4, "UB", -1, "", "Digital inputs 17 to 24"); //TI always included in gcl
499  map["_TI3"] = Source(5, "UB", -1, "", "Digital inputs 25 to 32");
500  map["_TI4"] = Source(6, "UB", -1, "", "Digital inputs 33 to 40");
501  map["_TI5"] = Source(7, "UB", -1, "", "Digital inputs 41 to 48");
502  map["_TI6"] = Source(8, "UB", -1, "", "Digital inputs 49 to 56");
503  map["_TI7"] = Source(9, "UB", -1, "", "Digital inputs 57 to 64");
504  map["_TI8"] = Source(10, "UB", -1, "", "Digital inputs 65 to 72");
505  map["_TI9"] = Source(11, "UB", -1, "", "Digital inputs 73 to 80");
506 
507  map["_OP1"] = Source(14, "UW", -1, "", "Digital outputs 17 to 32"); //OP always included in gcl
508  map["_OP2"] = Source(16, "UW", -1, "", "Digital outputs 33 to 48");
509  map["_OP3"] = Source(18, "UW", -1, "", "Digital outputs 49 to 64");
510  map["_OP4"] = Source(20, "UW", -1, "", "Digital outputs 65 to 80");
511 
512  if (co & 0x00000001) //bank 2 is output
513  output_bits(14, 17);
514  else //input
515  input_bits(4, 17);
516 
517  if (co & 0x00000002) //bank 3 is output
518  output_bits(15, 25);
519  else //input
520  input_bits(5, 25);
521 
522  if (co & 0x00000004) //bank 4 is output
523  output_bits(16, 33);
524  else //input
525  input_bits(6, 33);
526 
527  if (co & 0x00000008) //bank 5 is output
528  output_bits(17, 41);
529  else //input
530  input_bits(7, 41);
531 
532  if (co & 0x00000010) //bank 6 is output
533  output_bits(18, 49);
534  else //input
535  input_bits(8, 49);
536 
537  if (co & 0x00000020) //bank 7 is output
538  output_bits(19, 57);
539  else //input
540  input_bits(9, 57);
541 
542  if (co & 0x00000040) //bank 8 is output
543  output_bits(20, 65);
544  else //input
545  input_bits(10, 65);
546 
547  if (co & 0x00000080) //bank 9 is output
548  output_bits(21, 73);
549  else //input
550  input_bits(11, 73);
551  } //extended io
552 
553  map["_TC"] = Source(46, "UB", -1, "", "Error code");
554 
555  //Thread status
556  map["NO0"] = Source(47, "UB", 0, "Boolean", "Thread 0 running");
557  map["NO1"] = Source(47, "UB", 1, "Boolean", "Thread 1 running");
558  map["NO2"] = Source(47, "UB", 2, "Boolean", "Thread 2 running");
559  map["NO3"] = Source(47, "UB", 3, "Boolean", "Thread 3 running");
560  map["NO4"] = Source(47, "UB", 4, "Boolean", "Thread 4 running");
561  map["NO5"] = Source(47, "UB", 5, "Boolean", "Thread 5 running");
562  map["NO6"] = Source(47, "UB", 6, "Boolean", "Thread 6 running");
563  map["NO7"] = Source(47, "UB", 7, "Boolean", "Thread 7 running");
564 
565  //contour mode
566  map["CD"] = Source(52, "UL", -1, "segments", "Contour segment count");
567  map["_CM"] = Source(56, "UW", -1, "elements", "Contour buffer space");
568 
569  //S plane
570  map["_CSS"] = Source(58, "UW", -1, "segments", "Axis S segment count");
571  map["VDS"] = Source(60, "UB", 3, "Boolean", "Axis S final deceleration");
572  map["STS"] = Source(60, "UB", 4, "Boolean", "Axis S stopping");
573  map["VSS"] = Source(60, "UB", 5, "Boolean", "Axis S slewing");
574  map["_BGS"] = Source(61, "UB", 7, "Boolean", "Axis S moving");
575  map["_AVS"] = Source(62, "SL", -1, "counts", "Axis S length");
576  map["_LMS"] = Source(66, "UW", -1, "elements", "Axis S buffer speace");
577 
578  //T plane
579  map["_CST"] = Source(68, "UW", -1, "segments", "Axis T segment count");
580  map["VDT"] = Source(70, "UB", 3, "Boolean", "Axis T final deceleration");
581  map["STT"] = Source(70, "UB", 4, "Boolean", "Axis T stopping");
582  map["VST"] = Source(70, "UB", 5, "Boolean", "Axis T slewing");
583  map["_BGT"] = Source(71, "UB", 7, "Boolean", "Axis T moving");
584  map["_AVT"] = Source(72, "SL", -1, "counts", "Axis T length");
585  map["_LMT"] = Source(76, "UW", -1, "elements", "Axis T buffer speace");
586 
587  //per-axis data
588  int base = 78; //start of A axis data
589  for (int i = 0; i < axes; i++)
590  {
591  map[ax("_MO", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " motor off"));
592  map[ax("HM", i, "3")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " found index"));
593  map[ax("_AL", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " latch armed"));
594  map[ax("DC", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " began deceleration"));
595  map[ax("ST", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " began stop"));
596  map[ax("SP", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " began slew"));
597  map[ax("CM", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in contour mode"));
598  map[ax("JG", i, "-")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " negative move"));
599  ++base; //79
600  map[ax("VM", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " in VM or LI mode"));
601  map[ax("HM", i, "2")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " finding index"));
602  map[ax("HM", i, "1")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " coming off home switch"));
603  map[ax("HM", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " home command issued"));
604  map[ax("FE", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " find edge issued"));
605  map[ax("PA", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " in PA mode"));
606  map[ax("PR", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in PA or PR mode"));
607  map[ax("_BG", i, "")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " move in progress"));
608  ++base; //80
609  map[ax("MT", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " in stepper mode"));
610  map[ax("_HM", i, "")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " home switch"));
611  map[ax("_LR", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " reverse limit switch"));
612  map[ax("_LF", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " forward limit switch"));
613  //4 and 5 reserved
614  map[ax("AL", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch digital input"));
615  map[ax("_AL", i, "=0")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch occurred"));
616  ++base; //81
617  map[ax("_SC", i, "")] = Source(base, "UB", -1, "", ax("Axis ", i, " stop code"));
618  ++base; //82
619  map[ax("_RP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " reference position"));
620  base += 4; //86
621  map[ax("_TP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " encoder position"));
622  base += 4; //90
623  map[ax("_TE", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " position error"));
624  base += 4; //94
625  map[ax("_TD", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " dual encoder position"));
626  base += 4; //98
627  map[ax("_TV", i, "")] = Source(base, "SL", -1, "counts/s", ax("Axis ", i, " filtered velocity"), 64);
628  base += 4; //102
629  map[ax("_TT", i, "")] = Source(base, "SL", -1, "V", ax("Axis ", i, " torque (DAC)"), 3255);
630  base += 4; //106
631 
632  map["@AN[" + to_string(i + 1) + "]"] = Source(base, "SW", -1, "V", "Analog input " + to_string(i + 1), 3276.8);
633 
634  base += 2; //108 reserved
635  base += 1; //109 reserved
636  base += 1; //110
637  map[ax("_ZA", i, "")] = Source(base, "SL", -1, "", ax("Axis ", i, " user variable"));
638  base += 4; //114
639  }// for, axis data
640 }
641 
642 void GalilPrivate::Init1800(int axes, bool dmc1802)
643 {
644 
645  map["TIME"] = Source(0, "UW", -1, "samples", "Sample counter");
646 
647  //Digital Inputs
648  map["_TI0"] = Source(2, "UB", -1, "", "Digital inputs 1 to 8");
649  input_bits(2, 1);
650 
651  map["_TI1"] = Source(3, "UB", -1, "", "Digital inputs 9 to 16"); //TI always included
652  if (axes > 4) //9-16 depend on axes 5-8
653  input_bits(3, 9);
654 
655  //Digital outputs
656  map["_OP0"] = Source(12, "UW", -1, "", "Digital outputs 1 to 16");
657  output_bits(12, 1);
658  if (axes > 4) //9-16 depend on axes 5-8
659  output_bits(13, 9);
660 
661  //Extended I/O
662  int co = -1;
663  if (GCmdI(g, "MG_CO", &co) == G_NO_ERROR)
664  {
665  map["_TI2"] = Source(4, "UB", -1, "", "Digital inputs 17 to 24"); //TI always included in gcl
666  map["_TI3"] = Source(5, "UB", -1, "", "Digital inputs 25 to 32");
667  map["_TI4"] = Source(6, "UB", -1, "", "Digital inputs 33 to 40");
668  map["_TI5"] = Source(7, "UB", -1, "", "Digital inputs 41 to 48");
669  map["_TI6"] = Source(8, "UB", -1, "", "Digital inputs 49 to 56");
670  map["_TI7"] = Source(9, "UB", -1, "", "Digital inputs 57 to 64");
671  map["_TI8"] = Source(10, "UB", -1, "", "Digital inputs 65 to 72");
672  map["_TI9"] = Source(11, "UB", -1, "", "Digital inputs 73 to 80");
673 
674  map["_OP1"] = Source(14, "UW", -1, "", "Digital outputs 17 to 32"); //OP always included in gcl
675  map["_OP2"] = Source(16, "UW", -1, "", "Digital outputs 33 to 48");
676  map["_OP3"] = Source(18, "UW", -1, "", "Digital outputs 49 to 64");
677  map["_OP4"] = Source(20, "UW", -1, "", "Digital outputs 65 to 80");
678 
679  if (co & 0x00000001) //bank 2 is output
680  output_bits(14, 17);
681  else //input
682  input_bits(4, 17);
683 
684  if (co & 0x00000002) //bank 3 is output
685  output_bits(15, 25);
686  else //input
687  input_bits(5, 25);
688 
689  if (co & 0x00000004) //bank 4 is output
690  output_bits(16, 33);
691  else //input
692  input_bits(6, 33);
693 
694  if (co & 0x00000008) //bank 5 is output
695  output_bits(17, 41);
696  else //input
697  input_bits(7, 41);
698 
699  if (co & 0x00000010) //bank 6 is output
700  output_bits(18, 49);
701  else //input
702  input_bits(8, 49);
703 
704  if (co & 0x00000020) //bank 7 is output
705  output_bits(19, 57);
706  else //input
707  input_bits(9, 57);
708 
709  if (co & 0x00000040) //bank 8 is output
710  output_bits(20, 65);
711  else //input
712  input_bits(10, 65);
713 
714  if (co & 0x00000080) //bank 9 is output
715  output_bits(21, 73);
716  else //input
717  input_bits(11, 73);
718  } //extended io
719 
720  map["_TC"] = Source(22, "UB", -1, "", "Error code");
721 
722  //general status
723  map["_EO"] = Source(23, "UB", 0, "Boolean", "Echo on");
724  map["TR"] = Source(23, "UB", 1, "Boolean", "Trace on");
725  map["IN"] = Source(23, "UB", 2, "Boolean", "IN waiting for user input");
726  map["XQ"] = Source(23, "UB", 7, "Boolean", "Program running");
727 
728  //S plane
729  map["_CSS"] = Source(24, "UW", -1, "segments", "Axis S segment count");
730  map["VDS"] = Source(26, "UB", 3, "Boolean", "Axis S final deceleration");
731  map["STS"] = Source(26, "UB", 4, "Boolean", "Axis S stopping");
732  map["VSS"] = Source(26, "UB", 5, "Boolean", "Axis S slewing");
733  map["_BGS"] = Source(27, "UB", 7, "Boolean", "Axis S moving");
734  map["_AVS"] = Source(28, "SL", -1, "counts", "Axis S length");
735 
736  //T plane
737  map["_CST"] = Source(32, "UW", -1, "segments", "Axis T segment count");
738  map["VDT"] = Source(34, "UB", 3, "Boolean", "Axis T final deceleration");
739  map["STT"] = Source(34, "UB", 4, "Boolean", "Axis T stopping");
740  map["VST"] = Source(34, "UB", 5, "Boolean", "Axis T slewing");
741  map["_BGT"] = Source(35, "UB", 7, "Boolean", "Axis T moving");
742  map["_AVT"] = Source(36, "SL", -1, "counts", "Axis T length");
743 
744  //per-axis data
745  int base = 40; //start of A axis data
746  for (int i = 0; i < axes; i++)
747  {
748  map[ax("_MO", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " motor off"));
749  map[ax("_OE", i, "")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " off-on-error set"));
750  map[ax("_AL", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " latch armed"));
751  map[ax("DC", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " began deceleration"));
752  map[ax("ST", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " began stop"));
753  map[ax("SP", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " began slew"));
754  map[ax("CM", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in contour mode"));
755  map[ax("JG", i, "-")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " negative move"));
756  ++base; //41
757  map[ax("VM", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " in VM or LI mode"));
758  map[ax("HM", i, "2")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " finding index"));
759  map[ax("HM", i, "1")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " coming off home switch"));
760  map[ax("HM", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " home command issued"));
761  map[ax("FE", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " find edge issued"));
762  map[ax("PA", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " in PA mode"));
763  map[ax("PR", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in PA or PR mode"));
764  map[ax("_BG", i, "")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " move in progress"));
765  ++base; //42
766  map[ax("SM", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " stepper jumper installed"));
767  map[ax("_HM", i, "")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " home switch"));
768  map[ax("_LR", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " reverse limit switch"));
769  map[ax("_LF", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " forward limit switch"));
770  //4 and 5 reserved
771  map[ax("AL", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch digital input"));
772  map[ax("_AL", i, "=0")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch occurred"));
773  ++base; //43
774  map[ax("_SC", i, "")] = Source(base, "UB", -1, "", ax("Axis ", i, " stop code"));
775  ++base; //44
776  map[ax("_RP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " reference position"));
777  base += 4; //48
778  map[ax("_TP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " encoder position"));
779  base += 4; //52
780  map[ax("_TE", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " position error"));
781  base += 4; //56
782  map[ax("_TD", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " dual encoder position"));
783  base += 4; //60
784  map[ax("_TV", i, "")] = Source(base, "SL", -1, "counts/s", ax("Axis ", i, " filtered velocity"), 64);
785  base += 4; //64
786  map[ax("_TT", i, "")] = Source(base, "SW", -1, "V", ax("Axis ", i, " torque (DAC)"), 3255);
787  base += 2; //66
788 
789  if (!dmc1802) //1800 has onboard Analog inputs
790  map["@AN[" + to_string(i + 1) + "]"] = Source(base, "SW", -1, "V", "Analog input " + to_string(i + 1), 3276.8);
791 
792  base += 2; //68, pointing to next axis
793  } //for
794 }
795 
796 
797 void GalilPrivate::Init30010(bool dmc31010)
798 {
799  //0-3 Header is ignored in GCL
800 
801  map["TIME"] = Source(4, "UW", -1, "samples", "Sample counter");
802 
803  map["@IN[1]"] = Source(6, "UB", 0, "Boolean", "Digital input 1");
804  map["@IN[2]"] = Source(6, "UB", 1, "Boolean", "Digital input 2");
805  map["@IN[3]"] = Source(6, "UB", 2, "Boolean", "Digital input 3");
806  map["@IN[4]"] = Source(6, "UB", 3, "Boolean", "Digital input 4");
807  map["@IN[5]"] = Source(6, "UB", 4, "Boolean", "Digital input 5");
808  map["@IN[6]"] = Source(6, "UB", 5, "Boolean", "Digital input 6");
809  map["@IN[7]"] = Source(6, "UB", 6, "Boolean", "Digital input 7");
810  map["@IN[8]"] = Source(6, "UB", 7, "Boolean", "Digital input 8");
811 
812  map["@OUT[1]"] = Source(8, "UB", 0, "Boolean", "Digital output 1");
813  map["@OUT[2]"] = Source(8, "UB", 1, "Boolean", "Digital output 2");
814  map["@OUT[3]"] = Source(8, "UB", 2, "Boolean", "Digital output 3");
815  map["@OUT[4]"] = Source(8, "UB", 3, "Boolean", "Digital output 4");
816 
817  map["_TC"] = Source(10, "UB", -1, "", "Error code");
818 
819  //Thread status
820  map["NO0"] = Source(11, "UB", 0, "Boolean", "Thread 0 running");
821  map["NO1"] = Source(11, "UB", 1, "Boolean", "Thread 1 running");
822  map["NO2"] = Source(11, "UB", 2, "Boolean", "Thread 2 running");
823  map["NO3"] = Source(11, "UB", 3, "Boolean", "Thread 3 running");
824  map["NO4"] = Source(11, "UB", 4, "Boolean", "Thread 4 running"); //Firmware prior to 1.2a has only 4 threads
825  map["NO5"] = Source(11, "UB", 5, "Boolean", "Thread 5 running");
826 
827  //Analog IO
828  //version 1.1b provides 16 bit AQ-compatible data in data record
829  if (dmc31010)
830  aq_analog(12, 2);
831  else
832  map["@AN[2]"] = Source(12, "UW", -1, "V", "Analog input 2", 13107.2); //0-5 16 bit upsampling
833 
834  map["@AO[1]"] = Source(14, "SW", -1, "V", "Analog output 1", 3276.8); //+/- 10v
835  map["@AO[2]"] = Source(16, "SW", -1, "V", "Analog output 2", 3276.8);
836 
837  //Amp status
838  map["TA00"] = Source(18, "UB", 0, "Boolean", "Axis A over current");
839  map["TA01"] = Source(18, "UB", 1, "Boolean", "Axis A over voltage");
840  map["TA02"] = Source(18, "UB", 2, "Boolean", "Axis A over temperature");
841  map["TA03"] = Source(18, "UB", 3, "Boolean", "Axis A under voltage");
842  map["TA1A"] = Source(19, "UB", 0, "Boolean", "Axis A hall error");
843  map["TA2A"] = Source(20, "UB", 0, "Boolean", "Axis A at _TKA peak current");
844  map["TA3AD"] = Source(21, "UB", 0, "Boolean", "Axis A ELO active");
845 
846  //contour mode
847  map["CD"] = Source(22, "UL", -1, "segments", "Contour segment count");
848  map["_CM"] = Source(26, "UW", -1, "elements", "Contour buffer space");
849 
850  //S plane
851  map["_CSS"] = Source(28, "UW", -1, "segments", "Axis S segment count");
852  map["VDS"] = Source(30, "UB", 3, "Boolean", "Axis S final deceleration");
853  map["STS"] = Source(30, "UB", 4, "Boolean", "Axis S stopping");
854  map["VSS"] = Source(30, "UB", 5, "Boolean", "Axis S slewing");
855  map["_BGS"] = Source(31, "UB", 7, "Boolean", "Axis S moving");
856  map["_AVS"] = Source(32, "SL", -1, "counts", "Axis S length");
857  map["_LMS"] = Source(36, "UW", -1, "elements", "Axis S buffer speace");
858 
859  //per-axis data
860  int base = 38; //starting offset
861  int i = 0; //only one axis on 30010, no need to iterate axes
862 
863  map[ax("_MO", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " motor off"));
864  map[ax("HM", i, "3")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " found index"));
865  map[ax("_AL", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " latch armed"));
866  map[ax("DC", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " began deceleration"));
867  map[ax("ST", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " began stop"));
868  map[ax("SP", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " began slew"));
869  map[ax("CM", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in contour mode"));
870  map[ax("JG", i, "-")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " negative move"));
871  ++base; //39
872  map[ax("VM", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " in VM or LI mode"));
873  map[ax("HM", i, "2")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " finding index"));
874  map[ax("HM", i, "1")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " coming off home switch"));
875  map[ax("HM", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " home command issued"));
876  map[ax("FE", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " find edge issued"));
877  map[ax("PA", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " in PA mode"));
878  map[ax("PR", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in PA or PR mode"));
879  map[ax("_BG", i, "")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " move in progress"));
880  ++base; //40
881  map[ax("MT", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " in stepper mode"));
882  map[ax("_HM", i, "")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " home switch"));
883  map[ax("_LR", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " reverse limit switch"));
884  map[ax("_LF", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " forward limit switch"));
885  //4 and 5 reserved
886  map[ax("AL", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch digital input"));
887  map[ax("_AL", i, "=0")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch occurred"));
888  ++base; //41
889  map[ax("_SC", i, "")] = Source(base, "UB", -1, "", ax("Axis ", i, " stop code"));
890  ++base; //42
891  map[ax("_RP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " reference position"));
892  base += 4; //46
893  map[ax("_TP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " encoder position"));
894  base += 4; //50
895  map[ax("_TE", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " position error"));
896  base += 4; //54
897  map[ax("_TD", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " dual encoder position"));
898  base += 4; //58
899  map[ax("_TV", i, "")] = Source(base, "SL", -1, "counts/s", ax("Axis ", i, " filtered velocity"), 64);
900  base += 4; //62
901  map[ax("_TT", i, "")] = Source(base, "SL", -1, "V", ax("Axis ", i, " torque (DAC)"), 3255);
902  base += 4; //66
903 
904  //version 1.1b provides 16 bit AQ-compatible data in data record
905  if (dmc31010)
906  aq_analog(base, i + 1);
907  else
908  map["@AN[" + to_string(i + 1) + "]"] = Source(base, "UW", -1, "V", "Analog input " + to_string(i + 1), 13107.2);
909 
910  base += 2; //68
911 
912  map[ax("_QH", i, "")] = Source(base, "UB", -1, "", ax("Axis ", i, " hall sensors"));
913  base++; //69 reserved
914  base++; //70
915  map[ax("_ZA", i, "")] = Source(base, "SL", -1, "", ax("Axis ", i, " user variable"));
916  base += 4; //74
917 
918 }
919 
920 void GalilPrivate::Init2103(int axes)
921 {
922 
923  bool db28040 = (GCmd(g, "MG @AN[1]") == G_NO_ERROR); //probe @AN for existance of DB-28040
924 
925  //0-3 Header is ignored in GCL
926 
927  map["TIME"] = Source(4, "UW", -1, "samples", "Sample counter");
928 
929  //Digital Inputs
930  map["_TI0"] = Source(6, "UB", -1, "", "Digital inputs 1 to 8");
931  input_bits(6, 1);
932 
933  map["_TI1"] = Source(7, "UB", -1, "", "Digital inputs 9 to 16"); //TI always included
934  if (axes > 4) //9-16 depend on axes 5-8
935  input_bits(7, 9);
936 
937  //Digital outputs
938  map["_OP0"] = Source(16, "UW", -1, "", "Digital outputs 1 to 16");
939  output_bits(16, 1);
940 
941  if (axes > 4) //9-16 depend on axes 5-8
942  output_bits(17, 9);
943 
944  //Extended I/O
945  int co = -1;
946  if (db28040 && (GCmdI(g, "MG_CO", &co) == G_NO_ERROR))
947  {
948  map["_TI2"] = Source(8, "UB", -1, "", "Digital inputs 17 to 24"); //TI always included in gcl
949  map["_TI3"] = Source(9, "UB", -1, "", "Digital inputs 25 to 32");
950  map["_TI4"] = Source(10, "UB", -1, "", "Digital inputs 33 to 40");
951  map["_TI5"] = Source(11, "UB", -1, "", "Digital inputs 41 to 48");
952  map["_TI6"] = Source(12, "UB", -1, "", "Digital inputs 49 to 56");
953 
954  map["_OP1"] = Source(18, "UW", -1, "", "Digital outputs 17 to 32"); //OP always included in gcl
955  map["_OP2"] = Source(20, "UW", -1, "", "Digital outputs 33 to 48");
956  map["_OP3"] = Source(22, "UW", -1, "", "Digital outputs 49 to 64");
957 
958  if (co & 0x00000001) //bank 2 is output
959  output_bits(18, 17);
960  else //bank 2 in input
961  input_bits(8, 17);
962 
963  if (co & 0x00000002) //bank 3 is output
964  output_bits(19, 25);
965  else //bank 3 is input
966  input_bits(9, 25);
967 
968  if (co & 0x00000004) //bank 4 is output
969  output_bits(20, 33);
970  else //bank 4 is input
971  input_bits(10, 33);
972 
973  if (co & 0x00000008) //bank 5 is output
974  output_bits(21, 41);
975  else //bank 5 is input
976  input_bits(11, 41);
977 
978  if (co & 0x00000010) //bank 6 is output
979  output_bits(22, 49);
980  else //bank 6 is input
981  input_bits(12, 49);
982  }
983 
984  map["_TC"] = Source(26, "UB", -1, "", "Error code");
985 
986  //general status
987  map["_EO"] = Source(27, "UB", 0, "Boolean", "Echo on");
988  map["TR"] = Source(27, "UB", 1, "Boolean", "Trace on");
989  map["IN"] = Source(27, "UB", 2, "Boolean", "IN waiting for user input");
990  map["XQ"] = Source(27, "UB", 7, "Boolean", "Program running");
991 
992  //S plane
993  map["_CSS"] = Source(28, "UW", -1, "segments", "Axis S segment count");
994  map["VDS"] = Source(30, "UB", 3, "Boolean", "Axis S final deceleration");
995  map["STS"] = Source(30, "UB", 4, "Boolean", "Axis S stopping");
996  map["VSS"] = Source(30, "UB", 5, "Boolean", "Axis S slewing");
997  map["_BGS"] = Source(31, "UB", 7, "Boolean", "Axis S moving");
998  map["_AVS"] = Source(32, "SL", -1, "counts", "Axis S length");
999 
1000  //T plane
1001  map["_CST"] = Source(36, "UW", -1, "segments", "Axis T segment count");
1002  map["VDT"] = Source(38, "UB", 3, "Boolean", "Axis T final deceleration");
1003  map["STT"] = Source(38, "UB", 4, "Boolean", "Axis T stopping");
1004  map["VST"] = Source(38, "UB", 5, "Boolean", "Axis T slewing");
1005  map["_BGT"] = Source(39, "UB", 7, "Boolean", "Axis T moving");
1006  map["_AVT"] = Source(40, "SL", -1, "counts", "Axis T length");
1007 
1008  //per-axis data
1009  int base = 44; //start of A axis data
1010  for (int i = 0; i < axes; i++)
1011  {
1012  map[ax("_MO", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " motor off"));
1013  map[ax("_OE", i, "")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " off-on-error set"));
1014  map[ax("_AL", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " latch armed"));
1015  map[ax("DC", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " began deceleration"));
1016  map[ax("ST", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " began stop"));
1017  map[ax("SP", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " began slew"));
1018  map[ax("CM", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in contour mode"));
1019  map[ax("JG", i, "-")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " negative move"));
1020  ++base; //45
1021  map[ax("VM", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " in VM or LI mode"));
1022  map[ax("HM", i, "2")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " finding index"));
1023  map[ax("HM", i, "1")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " coming off home switch"));
1024  map[ax("HM", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " home command issued"));
1025  map[ax("FE", i, "")] = Source(base, "UW", 4, "Boolean", ax("Axis ", i, " find edge issued"));
1026  map[ax("PA", i, "")] = Source(base, "UW", 5, "Boolean", ax("Axis ", i, " in PA mode"));
1027  map[ax("PR", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " in PA or PR mode"));
1028  map[ax("_BG", i, "")] = Source(base, "UW", 7, "Boolean", ax("Axis ", i, " move in progress"));
1029  ++base; //46
1030  map[ax("SM", i, "")] = Source(base, "UW", 0, "Boolean", ax("Axis ", i, " stepper jumper installed"));
1031  map[ax("_HM", i, "")] = Source(base, "UW", 1, "Boolean", ax("Axis ", i, " home switch"));
1032  map[ax("_LR", i, "")] = Source(base, "UW", 2, "Boolean", ax("Axis ", i, " reverse limit switch"));
1033  map[ax("_LF", i, "")] = Source(base, "UW", 3, "Boolean", ax("Axis ", i, " forward limit switch"));
1034  //4 and 5 reserved
1035  map[ax("AL", i, "")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch digital input"));
1036  map[ax("_AL", i, "=0")] = Source(base, "UW", 6, "Boolean", ax("Axis ", i, " latch occurred"));
1037  ++base; //47
1038  map[ax("_SC", i, "")] = Source(base, "UB", -1, "", ax("Axis ", i, " stop code"));
1039  ++base; //48
1040  map[ax("_RP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " reference position"));
1041  base += 4; //52
1042  map[ax("_TP", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " encoder position"));
1043  base += 4; //56
1044  map[ax("_TE", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " position error"));
1045  base += 4; //60
1046  map[ax("_TD", i, "")] = Source(base, "SL", -1, "counts", ax("Axis ", i, " dual encoder position"));
1047  base += 4; //64
1048  map[ax("_TV", i, "")] = Source(base, "SL", -1, "counts/s", ax("Axis ", i, " filtered velocity"), 64);
1049  base += 4; //68
1050  map[ax("_TT", i, "")] = Source(base, "SW", -1, "V", ax("Axis ", i, " torque (DAC)"), 3255);
1051  base += 2; //70
1052 
1053  if (db28040) //card has onboard Analog inputs
1054  {
1055  aq_analog(base, i + 1); //map in the analog
1056  }
1057  base += 2; //72
1058  } //for
1059 }
1060 
1061 void GalilPrivate::InitRio(bool rio3)
1062 {
1063 
1064 
1065  //0-3 Header is ignored in GCL
1066 
1067  map["TIME"] = Source(4, "UW", -1, "samples", "Sample counter");
1068  map["_TC"] = Source(6, "UB", -1, "", "Error code");
1069 
1070  //general status
1071  map["_EO"] = Source(7, "UB", 0, "Boolean", "Echo on");
1072  map["TR"] = Source(7, "UB", 1, "Boolean", "Trace on");
1073  map["IN"] = Source(7, "UB", 2, "Boolean", "IN waiting for user input");
1074  map["XQ"] = Source(7, "UB", 7, "Boolean", "Program running");
1075 
1076  bool aqdq = (q->command("ID").find("(AQ)") != string::npos); //progammable analog I/O
1077 
1078  if (aqdq)
1079  {
1080  dq_analog(8, 0);
1081  dq_analog(10, 1);
1082  dq_analog(12, 2);
1083  dq_analog(14, 3);
1084  dq_analog(16, 4);
1085  dq_analog(18, 5);
1086  dq_analog(20, 6);
1087  dq_analog(22, 7);
1088  }
1089  else //fixed 0-5V
1090  {
1091  map["@AO[0]"] = Source(8, "UW", -1, "V", "Analog output 0", 13107.2, 0);
1092  map["@AO[1]"] = Source(10, "UW", -1, "V", "Analog output 1", 13107.2, 0);
1093  map["@AO[2]"] = Source(12, "UW", -1, "V", "Analog output 2", 13107.2, 0);
1094  map["@AO[3]"] = Source(14, "UW", -1, "V", "Analog output 3", 13107.2, 0);
1095  map["@AO[4]"] = Source(16, "UW", -1, "V", "Analog output 4", 13107.2, 0);
1096  map["@AO[5]"] = Source(18, "UW", -1, "V", "Analog output 5", 13107.2, 0);
1097  map["@AO[6]"] = Source(20, "UW", -1, "V", "Analog output 6", 13107.2, 0);
1098  map["@AO[7]"] = Source(22, "UW", -1, "V", "Analog output 7", 13107.2, 0);
1099  }
1100 
1101 
1102  if (aqdq)
1103  {
1104  aq_analog(24, 0);
1105  aq_analog(26, 1);
1106  aq_analog(28, 2);
1107  aq_analog(30, 3);
1108  aq_analog(32, 4);
1109  aq_analog(34, 5);
1110  aq_analog(36, 6);
1111  aq_analog(38, 7);
1112  }
1113  else //fixed 0-5V
1114  {
1115  map["@AN[0]"] = Source(24, "UW", -1, "V", "Analog input 0", 13107.2, 0);
1116  map["@AN[1]"] = Source(26, "UW", -1, "V", "Analog input 1", 13107.2, 0);
1117  map["@AN[2]"] = Source(28, "UW", -1, "V", "Analog input 2", 13107.2, 0);
1118  map["@AN[3]"] = Source(30, "UW", -1, "V", "Analog input 3", 13107.2, 0);
1119  map["@AN[4]"] = Source(32, "UW", -1, "V", "Analog input 4", 13107.2, 0);
1120  map["@AN[5]"] = Source(34, "UW", -1, "V", "Analog input 5", 13107.2, 0);
1121  map["@AN[6]"] = Source(36, "UW", -1, "V", "Analog input 6", 13107.2, 0);
1122  map["@AN[7]"] = Source(38, "UW", -1, "V", "Analog input 7", 13107.2, 0);
1123  }
1124 
1125  //Data record diverges here for RIO471/472 and RIO473
1126  int base = 40;
1127 
1128  //outputs
1129  map["_OP0"] = Source(base, "UB", -1, "", "Digital ouputs 0-7");
1130  output_bits(base, 0);
1131  base++;
1132 
1133  map["_OP1"] = Source(base, "UB", -1, "", "Digital outputs 8-15");
1134  output_bits(base, 8);
1135  base++;
1136 
1137  if (rio3)
1138  {
1139  map["_OP2"] = Source(base, "UB", -1, "", "Digital outputs 16-23");
1140  output_bits(base, 16);
1141  base++;
1142  base++; //one more byte in IO space
1143  }
1144 
1145  //inputs
1146  map["_TI0"] = Source(base, "UB", -1, "", "Digital inputs 0-7");
1147  input_bits(base, 0);
1148  base++;
1149 
1150  map["_TI1"] = Source(base, "UB", -1, "", "Digital inputs 8-15");
1151  input_bits(base, 8);
1152  base++;
1153 
1154  if (rio3)
1155  {
1156  map["_TI2"] = Source(base, "UB", -1, "", "Digital inputs 16-23");
1157  input_bits(base, 16);
1158  base++;
1159  base++; //one more byte in IO space
1160  }
1161 
1162  //pulse counter
1163  map["_PC"] = Source(base, "UL", -1, "edges", "Pulse counter");
1164  base += 4;
1165 
1166  //user vars
1167  map["_ZC"] = Source(base, "SL", -1, "", "1st user variable");
1168  base += 4;
1169  map["_ZD"] = Source(base, "SL", -1, "", "2nd user variable");
1170  base += 4;
1171 }
1172 
1173 void GalilPrivate::InitRio3_24Ex()
1174 {
1175  //Extended I/O tacks 8 bytes on the end of the data record, three bytes of each of I/O, one reserved for each
1176  map["_OP3"] = Source(60, "UB", -1, "", "Digital outputs 24-31");
1177  output_bits(60, 24);
1178  map["_OP4"] = Source(61, "UB", -1, "", "Digital outputs 32-39");
1179  output_bits(61, 32);
1180  map["_OP5"] = Source(62, "UB", -1, "", "Digital outputs 40-47");
1181  output_bits(62, 40);
1182  //byte 63 is reserved
1183 
1184  map["_TI3"] = Source(64, "UB", -1, "", "Digital inputs 24-31");
1185  input_bits(64, 24);
1186  map["_TI4"] = Source(65, "UB", -1, "", "Digital inputs 32-39");
1187  input_bits(65, 32);
1188  map["_TI5"] = Source(66, "UB", -1, "", "Digital inputs 40-47");
1189  input_bits(66, 40);
1190  //byte 67 is reserved
1191 }
1192 
1193 void GalilPrivate::InitRioSer(bool rio3)
1194 {
1195  //SER tacks 4 longs on the end of the data record (4 encoders)
1196  int base = rio3 ? 60 : 56; //RIO 47300 base data record is longer than the other RIO products due to 24 i/o standard
1197  map["_QE0"] = Source(base, "SL", -1, "counts", "encoder position"); base += 4;
1198  map["_QE1"] = Source(base, "SL", -1, "counts", "encoder position"); base += 4;
1199  map["_QE2"] = Source(base, "SL", -1, "counts", "encoder position"); base += 4;
1200  map["_QE3"] = Source(base, "SL", -1, "counts", "encoder position"); base += 4;
1201 }
GCLIB_DLL_EXPORTED GReturn GCALL GRecord(GCon g, union GDataRecord *record, GOption method)
Provides a fresh copy of the controller's data record. Data is cast into a union, GDataRecord.
GCLIB_DLL_EXPORTED GReturn GCALL GRecordRate(GCon g, double period_ms)
Sets the asynchronous data record to a user-specified period via DR.
Definition: gclibo.c:342
GCLIB_DLL_EXPORTED 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:278
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
#define G_DR
Value for GRecord() method variable for acquiring a data record via DR mode.
Definition: gclib.h:50
#define G_NO_ERROR
Return value if function succeeded.
Definition: gclib_errors.h:13
#define G_QR
Value for GRecord() method variable for acquiring a data record via QR mode.
Definition: gclib.h:51
void e(GReturn rc)
A trivial, C++ style return code check used in Galil's examples and demos.
Definition: examples.h:33
Data record union, containing all structs and a generic byte array accessor.
unsigned char byte_array[GALILDATARECORDMAXLENGTH]
Generic byte array for offsets.