/ src / emc / task / iotaskintf.cc
iotaskintf.cc
  1  /********************************************************************
  2  * Description: iotaskintf.cc
  3  *   NML interface functions for IO
  4  *
  5  *   Based on a work by Fred Proctor & Will Shackleford
  6  *
  7  * Author:
  8  * License: GPL Version 2
  9  * System: Linux
 10  *    
 11  * Copyright (c) 2004 All rights reserved.
 12  *
 13  * Last change:
 14  ********************************************************************/
 15  
 16  #include <math.h>		// fabs()
 17  #include <float.h>		// DBL_MAX
 18  #include <string.h>		// memcpy() strncpy()
 19  #include <stdlib.h>		// malloc()
 20  
 21  #include "rcs.hh"		// RCS_CMD_CHANNEL, etc.
 22  #include "rcs_print.hh"
 23  #include "timer.hh"             // esleep, etc.
 24  #include "emc.hh"		// EMC NML
 25  #include "emc_nml.hh"
 26  #include "emcglb.h"		// EMC_INIFILE
 27  
 28  #include "initool.hh"
 29  
 30  // IO INTERFACE
 31  
 32  // the NML channels to the EMCIO controller
 33  static RCS_CMD_CHANNEL *emcIoCommandBuffer = 0;
 34  static RCS_STAT_CHANNEL *emcIoStatusBuffer = 0;
 35  
 36  // global status structure
 37  EMC_IO_STAT *emcIoStatus = 0;
 38  
 39  // serial number for communication
 40  static int emcIoCommandSerialNumber = 0;
 41  static double EMCIO_BUFFER_GET_TIMEOUT = 5.0;
 42  
 43  static int forceCommand(RCS_CMD_MSG *msg);
 44  
 45  static int emcioNmlGet()
 46  {
 47      int retval = 0;
 48      double start_time;
 49      RCS_PRINT_DESTINATION_TYPE orig_dest;
 50      if (emcIoCommandBuffer == 0) {
 51  	orig_dest = get_rcs_print_destination();
 52  	set_rcs_print_destination(RCS_PRINT_TO_NULL);
 53  	start_time = etime();
 54  	while (start_time - etime() < EMCIO_BUFFER_GET_TIMEOUT) {
 55  	    emcIoCommandBuffer =
 56  		new RCS_CMD_CHANNEL(emcFormat, "toolCmd", "emc",
 57  				    emc_nmlfile);
 58  	    if (!emcIoCommandBuffer->valid()) {
 59  		delete emcIoCommandBuffer;
 60  		emcIoCommandBuffer = 0;
 61  	    } else {
 62  		break;
 63  	    }
 64  	    esleep(0.1);
 65  	}
 66  	set_rcs_print_destination(orig_dest);
 67      }
 68  
 69      if (emcIoCommandBuffer == 0) {
 70  	emcIoCommandBuffer =
 71  	    new RCS_CMD_CHANNEL(emcFormat, "toolCmd", "emc", emc_nmlfile);
 72  	if (!emcIoCommandBuffer->valid()) {
 73  	    delete emcIoCommandBuffer;
 74  	    emcIoCommandBuffer = 0;
 75  	    retval = -1;
 76  	}
 77      }
 78  
 79      if (emcIoStatusBuffer == 0) {
 80  	orig_dest = get_rcs_print_destination();
 81  	set_rcs_print_destination(RCS_PRINT_TO_NULL);
 82  	start_time = etime();
 83  	while (start_time - etime() < EMCIO_BUFFER_GET_TIMEOUT) {
 84  	    emcIoStatusBuffer =
 85  		new RCS_STAT_CHANNEL(emcFormat, "toolSts", "emc",
 86  				     emc_nmlfile);
 87  	    if (!emcIoStatusBuffer->valid()) {
 88  		delete emcIoStatusBuffer;
 89  		emcIoStatusBuffer = 0;
 90  	    } else {
 91  		emcIoStatus =
 92  		    (EMC_IO_STAT *) emcIoStatusBuffer->get_address();
 93  		break;
 94  	    }
 95  	    esleep(0.1);
 96  	}
 97  	set_rcs_print_destination(orig_dest);
 98      }
 99  
100      if (emcIoStatusBuffer == 0) {
101  	emcIoStatusBuffer =
102  	    new RCS_STAT_CHANNEL(emcFormat, "toolSts", "emc", emc_nmlfile);
103  	if (!emcIoStatusBuffer->valid()
104  	    || EMC_IO_STAT_TYPE != emcIoStatusBuffer->peek()) {
105  	    delete emcIoStatusBuffer;
106  	    emcIoStatusBuffer = 0;
107  	    emcIoStatus = 0;
108  	    retval = -1;
109  	} else {
110  	    emcIoStatus = (EMC_IO_STAT *) emcIoStatusBuffer->get_address();
111  	}
112      }
113  
114      return retval;
115  }
116  
117  static RCS_CMD_MSG *last_io_command = 0;
118  static long largest_io_command_size = 0;
119  
120  /*
121    sendCommand() waits until any currently executing command has finished,
122    then writes the given command.*/
123  /*! \todo
124    FIXME: Not very RCS-like to wait for status done here. (wps)
125  */
126  static int sendCommand(RCS_CMD_MSG * msg)
127  {
128      // need command buffer to be there
129      if (0 == emcIoCommandBuffer) {
130  	return -1;
131      }
132      // need status buffer also, to check for command received
133      if (0 == emcIoStatusBuffer || !emcIoStatusBuffer->valid()) {
134  	return -1;
135      }
136  
137      // always force-queue an abort
138      if (msg->type == EMC_TOOL_ABORT_TYPE) {
139  	// just queue the abort and call it a day
140  	int rc = forceCommand(msg);
141  	if (rc) {
142  	    rcs_print_error("forceCommand(EMC_TOOL_ABORT) returned %d\n", rc);
143  	}
144  	return 0;
145      }
146  
147      double send_command_timeout = etime() + 5.0;
148  
149      // check if we're executing, and wait until we're done
150      int serial_diff = 0;
151      while (etime() < send_command_timeout) {
152  	emcIoStatusBuffer->peek();
153  	serial_diff = emcIoStatus->echo_serial_number - emcIoCommandSerialNumber;
154  	if (serial_diff < 0 || emcIoStatus->status == RCS_EXEC) {
155  	    esleep(0.001);
156  	    continue;
157  	} else {
158  	    break;
159  	}
160      }
161  
162      if (serial_diff < 0 || emcIoStatus->status == RCS_EXEC) {
163  	// Still not done, must have timed out.
164  	rcs_print_error
165  	    ("Command to IO level (%s:%s) timed out waiting for last command done. \n",
166  	     emcSymbolLookup(msg->type), emcIoCommandBuffer->msg2str(msg));
167  	rcs_print_error
168  	    ("emcIoStatus->echo_serial_number=%d, emcIoCommandSerialNumber=%d, emcIoStatus->status=%d\n",
169  	     emcIoStatus->echo_serial_number, emcIoCommandSerialNumber,
170  	     emcIoStatus->status);
171  	if (0 != last_io_command) {
172  	    rcs_print_error("Last command sent to IO level was (%s:%s)\n",
173  			    emcSymbolLookup(last_io_command->type),
174  			    emcIoCommandBuffer->msg2str(last_io_command));
175  	}
176  	return -1;
177      }
178      // now we can send
179      if (0 != emcIoCommandBuffer->write(msg)) {
180  	rcs_print_error("Failed to send command to  IO level (%s:%s)\n",
181  			emcSymbolLookup(msg->type),
182  			emcIoCommandBuffer->msg2str(msg));
183  	return -1;
184      }
185      emcIoCommandSerialNumber = msg->serial_number;
186  
187      if (largest_io_command_size < msg->size) {
188  	largest_io_command_size = std::max<long>(msg->size, 4096);
189  	last_io_command = (RCS_CMD_MSG *) realloc(last_io_command, largest_io_command_size);
190      }
191  
192      if (0 != last_io_command) {
193  	memcpy(last_io_command, msg, msg->size);
194      }
195  
196      return 0;
197  }
198  
199  /*
200    forceCommand() writes the given command regardless of the executing
201    status of any previous command.
202  */
203  static int forceCommand(RCS_CMD_MSG * msg)
204  {
205      // need command buffer to be there
206      if (0 == emcIoCommandBuffer) {
207  	return -1;
208      }
209      // need status buffer also, to check for command received
210      if (0 == emcIoStatusBuffer || !emcIoStatusBuffer->valid()) {
211  	return -1;
212      }
213      // send it immediately
214      if (0 != emcIoCommandBuffer->write(msg)) {
215  	rcs_print_error("Failed to send command to  IO level (%s:%s)\n",
216  			emcSymbolLookup(msg->type),
217  			emcIoCommandBuffer->msg2str(msg));
218  	return -1;
219      }
220      emcIoCommandSerialNumber = msg->serial_number;
221  
222      if (largest_io_command_size < msg->size) {
223  	largest_io_command_size = std::max<long>(msg->size, 4096);
224  	last_io_command = (RCS_CMD_MSG *) realloc(last_io_command, largest_io_command_size);
225      }
226  
227      if (0 != last_io_command) {
228  	memcpy(last_io_command, msg, msg->size);
229      }
230  
231      return 0;
232  }
233  
234  // NML commands
235  
236  int emcIoInit()
237  {
238      EMC_TOOL_INIT ioInitMsg;
239  
240      // get NML buffer to emcio
241      if (0 != emcioNmlGet()) {
242  	rcs_print_error("emcioNmlGet() failed.\n");
243  	return -1;
244      }
245  
246      if (0 != iniTool(emc_inifile)) {
247  	return -1;
248      }
249      // send init command to emcio
250      if (forceCommand(&ioInitMsg)) {
251  	rcs_print_error("Can't forceCommand(ioInitMsg)\n");
252  	return -1;
253      }
254  
255      return 0;
256  }
257  
258  int emcIoHalt()
259  {
260      EMC_TOOL_HALT ioHaltMsg;
261  
262      // send halt command to emcio
263      if (emcIoCommandBuffer != 0) {
264  	forceCommand(&ioHaltMsg);
265      }
266      // clear out the buffers
267  
268      if (emcIoStatusBuffer != 0) {
269  	delete emcIoStatusBuffer;
270  	emcIoStatusBuffer = 0;
271  	emcIoStatus = 0;
272      }
273  
274      if (emcIoCommandBuffer != 0) {
275  	delete emcIoCommandBuffer;
276  	emcIoCommandBuffer = 0;
277      }
278  
279      if (last_io_command) {
280          free(last_io_command);
281          last_io_command = 0;
282      }
283  
284      return 0;
285  }
286  
287  int emcIoAbort(int reason)
288  {
289      EMC_TOOL_ABORT ioAbortMsg;
290  
291      ioAbortMsg.reason = reason;
292      // send abort command to emcio
293      sendCommand(&ioAbortMsg);
294  
295      return 0;
296  }
297  
298  int emcIoSetDebug(int debug)
299  {
300      EMC_SET_DEBUG ioDebugMsg;
301  
302      ioDebugMsg.debug = debug;
303  
304      return sendCommand(&ioDebugMsg);
305  }
306  
307  int emcAuxEstopOn()
308  {
309      EMC_AUX_ESTOP_ON estopOnMsg;
310  
311      return forceCommand(&estopOnMsg);
312  }
313  
314  int emcAuxEstopOff()
315  {
316      EMC_AUX_ESTOP_OFF estopOffMsg;
317  
318      return forceCommand(&estopOffMsg); //force the EstopOff message
319  }
320  
321  int emcCoolantMistOn()
322  {
323      EMC_COOLANT_MIST_ON mistOnMsg;
324  
325      sendCommand(&mistOnMsg);
326  
327      return 0;
328  }
329  
330  int emcCoolantMistOff()
331  {
332      EMC_COOLANT_MIST_OFF mistOffMsg;
333  
334      sendCommand(&mistOffMsg);
335  
336      return 0;
337  }
338  
339  int emcCoolantFloodOn()
340  {
341      EMC_COOLANT_FLOOD_ON floodOnMsg;
342  
343      sendCommand(&floodOnMsg);
344  
345      return 0;
346  }
347  
348  int emcCoolantFloodOff()
349  {
350      EMC_COOLANT_FLOOD_OFF floodOffMsg;
351  
352      sendCommand(&floodOffMsg);
353  
354      return 0;
355  }
356  
357  int emcLubeOn()
358  {
359      EMC_LUBE_ON lubeOnMsg;
360  
361      sendCommand(&lubeOnMsg);
362  
363      return 0;
364  }
365  
366  int emcLubeOff()
367  {
368      EMC_LUBE_OFF lubeOffMsg;
369  
370      sendCommand(&lubeOffMsg);
371  
372      return 0;
373  }
374  
375  int emcToolPrepare(int p, int tool)
376  {
377      EMC_TOOL_PREPARE toolPrepareMsg;
378  
379      toolPrepareMsg.pocket = p;
380      toolPrepareMsg.tool = tool;
381      sendCommand(&toolPrepareMsg);
382  
383      return 0;
384  }
385  
386  
387  int emcToolStartChange()
388  {
389      EMC_TOOL_START_CHANGE toolStartChangeMsg;
390  
391      sendCommand(&toolStartChangeMsg);
392  
393      return 0;
394  }
395  
396  
397  int emcToolLoad()
398  {
399      EMC_TOOL_LOAD toolLoadMsg;
400  
401      sendCommand(&toolLoadMsg);
402  
403      return 0;
404  }
405  
406  int emcToolUnload()
407  {
408      EMC_TOOL_UNLOAD toolUnloadMsg;
409  
410      sendCommand(&toolUnloadMsg);
411  
412      return 0;
413  }
414  
415  int emcToolLoadToolTable(const char *file)
416  {
417      EMC_TOOL_LOAD_TOOL_TABLE toolLoadToolTableMsg;
418  
419      strcpy(toolLoadToolTableMsg.file, file);
420  
421      sendCommand(&toolLoadToolTableMsg);
422  
423      return 0;
424  }
425  
426  int emcToolSetOffset(int pocket, int toolno, EmcPose offset, double diameter,
427                       double frontangle, double backangle, int orientation)
428  {
429      EMC_TOOL_SET_OFFSET toolSetOffsetMsg;
430  
431      toolSetOffsetMsg.pocket = pocket;
432      toolSetOffsetMsg.toolno = toolno;
433      toolSetOffsetMsg.offset = offset;
434      toolSetOffsetMsg.diameter = diameter;
435      toolSetOffsetMsg.frontangle = frontangle;
436      toolSetOffsetMsg.backangle = backangle;
437      toolSetOffsetMsg.orientation = orientation;
438  
439      sendCommand(&toolSetOffsetMsg);
440  
441      return 0;
442  }
443  
444  int emcToolSetNumber(int number)
445  {
446      EMC_TOOL_SET_NUMBER toolSetNumberMsg;
447  
448      toolSetNumberMsg.tool = number;
449  
450      sendCommand(&toolSetNumberMsg);
451  
452      return 0;
453  }
454  
455  // Status functions
456  
457  int emcIoUpdate(EMC_IO_STAT * stat)
458  {
459  
460      if (0 == emcIoStatusBuffer || !emcIoStatusBuffer->valid()) {
461  	return -1;
462      }
463  
464      switch (emcIoStatusBuffer->peek()) {
465      case -1:
466  	// error on CMS channel
467  	return -1;
468  	break;
469  
470      case 0:			// nothing new
471      case EMC_IO_STAT_TYPE:	// something new
472  	// drop out to copy
473  	break;
474  
475      default:
476  	// something else is in there
477  	return -1;
478  	break;
479      }
480  
481      // copy status
482      *stat = *emcIoStatus;
483  
484      /*
485         We need to check that the RCS_DONE isn't left over from the previous
486         command, by comparing the command number we sent with the command
487         number that emcio echoes. If they're different, then the command
488         hasn't been acknowledged yet and the state should be forced to be
489         RCS_EXEC. */
490      int serial_diff = emcIoStatus->echo_serial_number - emcIoCommandSerialNumber;
491      if (serial_diff < 0) {
492  	stat->status = RCS_EXEC;
493      }
494      //commented out because it keeps resetting the spindle speed to some odd value
495      //the speed gets set by the IO controller, no need to override it here (io takes care of increase/decrease speed too)
496      // stat->spindle.speed = spindleSpeed;
497  
498      return 0;
499  }