コード例 #1
0
ファイル: d_src_mono.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mxd_src_mono_move_absolute( MX_MOTOR *motor )
{
	static const char fname[] = "mxd_src_mono_move_absolute()";

	MX_SRC_MONO *src_mono = NULL;
	char command[200];
	char response[200];
	mx_status_type mx_status;

	mx_status = mxd_src_mono_get_pointers( motor, &src_mono, NULL, fname );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* Send the move command. */

	snprintf( command, sizeof(command),
		"SCANEV(%f)", motor->raw_destination.analog );

	mx_status = mx_rs232_putline( src_mono->rs232_record,
				command, NULL, MXD_SRC_MONO_DEBUG );

	if ( mx_status.code != MXE_SUCCESS ) {
		src_mono->state = MXS_SRC_MONO_ERROR;
		return mx_status;
	}

	/* If all went well, we should get a wait response from
	 * the SRC computer.
	 */

	mx_status = mx_rs232_getline( src_mono->rs232_record,
					response, sizeof(response),
					NULL, MXD_SRC_MONO_DEBUG );

	if ( mx_status.code == MXE_TIMED_OUT ) {
		src_mono->state = MXS_SRC_MONO_TIMED_OUT;
	} else
	if ( mx_status.code != MXE_SUCCESS ) {
		src_mono->state = MXS_SRC_MONO_ERROR;
	} else {
		if ( strcmp( response, "Wait!" ) == 0 ) {
			src_mono->state = MXS_SRC_MONO_ACTIVE;
		} else {
			src_mono->state = MXS_SRC_MONO_ERROR;

			mx_status = mx_error(MXE_DEVICE_IO_ERROR, fname,
			"Received unexpected response '%s' from "
			"SRC monochromator '%s'.",
				response, motor->record->name );
		}
	}

	return mx_status;
}
コード例 #2
0
ファイル: d_uglide.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mxd_uglide_soft_abort( MX_MOTOR *motor )
{
	static const char fname[] = "mxd_uglide_soft_abort()";

	MX_UGLIDE_MOTOR *uglide_motor;
	MX_UGLIDE *uglide;
	mx_status_type mx_status;

	mx_status = mxd_uglide_get_pointers( motor,
					&uglide_motor, &uglide, fname );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	MX_DEBUG( 2,("%s invoked for motor '%s'.", fname, motor->record->name));

	/* Send the single character 's' to the controller. */

#if UGLIDE_DEBUG
	MX_DEBUG(-2,("%s: sending soft abort character 's' to '%s'",
			fname, uglide->record->name ));
#endif

	mx_status = mx_rs232_putline( uglide->rs232_record, "s", NULL, 0 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* Wait a moment for the move to stop and then discard all
	 * existing responses from the controller.
	 */

	mx_msleep(500);

	mx_status = mx_rs232_discard_unread_input( uglide->rs232_record,
							UGLIDE_DEBUG );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* Tell the controller record that the last command executed was
	 * a position report.
	 */

	uglide->last_response_code = MXF_UGLIDE_POSITION_REPORT;

	/* Refresh the position of the motors. */

	mx_status = mxi_uglide_command( uglide, "q", UGLIDE_DEBUG );

	return mx_status;
}
コード例 #3
0
ファイル: i_isobus.c プロジェクト: amba/lab-measurement
MX_EXPORT mx_status_type
mxi_isobus_command( MX_ISOBUS *isobus,
		long isobus_address,
		char *command,
		char *response,
		size_t max_response_length,
		long maximum_retries,
		unsigned long isobus_flags )
{
	static const char fname[] = "mxi_isobus_command()";

	MX_RECORD *interface_record;
	long gpib_address;
	char local_command_buffer[100];
	char *command_ptr;
	size_t length;
	long i, j, rs232_retries;
	unsigned long wait_ms, num_input_bytes_available;
	mx_bool_type error_occurred;
	mx_status_type mx_status;

	if ( isobus == (MX_ISOBUS *) NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"The MX_ISOBUS pointer passed was NULL." );
	}
	if ( command == (char *) NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"The command pointer passed was NULL." );
	}

	interface_record = isobus->isobus_interface.record;

	if ( interface_record == (MX_RECORD *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
	    "The interface record pointer for ISOBUS interface '%s' is NULL.",
			isobus->record->name );
	}

	/* Format the command to be sent. */

	if ( isobus_address < 0 ) {
		command_ptr = command;
	} else {
		command_ptr = local_command_buffer;

		snprintf( local_command_buffer, sizeof(local_command_buffer),
			"@%ld%s", isobus_address, command );
	}

	if ( maximum_retries < 0 ) {
		maximum_retries = LONG_MAX;
	}

	error_occurred = FALSE;

	for ( i = 0; i <= maximum_retries; i++ ) {

		if ( i > 0 ) {
			mx_info( "ISOBUS interface '%s' command retry #%ld.",
				isobus->record->name, i );
		}

		/* Send the command and get the response. */

		if ( isobus_flags & MXF_ISOBUS_DEBUG ) {

			MX_DEBUG(-2,("%s: sending command '%s' to '%s'.",
			    fname, command_ptr, isobus->record->name));
		}

		error_occurred = FALSE;

		if ( interface_record->mx_class == MXI_RS232 ) {
			mx_status = mx_rs232_putline( interface_record,
						command_ptr, NULL, 0 );

			if ( mx_status.code != MXE_SUCCESS )
				return mx_status;

			if ( response != NULL ) {
				/* Wait for the response. */

				rs232_retries = 50;
				wait_ms = 100;

				for ( j = 0; j <= rs232_retries; j++ ) {

					/* See if the first character
					 * has arrived.
					 */

					mx_status =
					  mx_rs232_num_input_bytes_available(
						interface_record,
						&num_input_bytes_available );

					if ( mx_status.code != MXE_SUCCESS ) {
						/* Exit the for(j) loop. */

						break;  
					}

					if ( num_input_bytes_available > 0 ) {
						/* Exit the for(j) loop. */

						break;  
					}
				}

				if ( mx_status.code != MXE_SUCCESS ) {
					error_occurred = TRUE;
				} else {
					/* Read in the response. */

					mx_status = mx_rs232_getline(
						interface_record, response,
						max_response_length, NULL, 0);

					if ( mx_status.code != MXE_SUCCESS ) {
						error_occurred = TRUE;
					} else {
						/* Remove any trailing carriage
						 * return characters.
						 */

						length = strlen( response );

						if (length <
							max_response_length )
						{
							if ( response[length-1]
								== MX_CR )
							{
							    response[length-1]
								= '\0';
							}
						}
					}
				}
			}
		} else {	/* GPIB */

			gpib_address = isobus->isobus_interface.address;

			mx_status = mx_gpib_putline(
						interface_record, gpib_address,
						command_ptr, NULL, 0 );

			if ( mx_status.code != MXE_SUCCESS )
				return mx_status;

			if ( response != NULL ) {
				mx_status = mx_gpib_getline(
					interface_record, gpib_address,
					response, max_response_length, NULL, 0);

				if ( mx_status.code != MXE_SUCCESS ) {
					error_occurred = TRUE;
				}
			}
		}

		if ( error_occurred == FALSE ) {

			/* If the first character in the response is a
			 * question mark '?', then an error occurred.
			 */

			if ( response != NULL ) {
				if ( response[0] == '?' ) {

					mx_status = mx_error(
						MXE_DEVICE_ACTION_FAILED, fname,
			"The command '%s' to ISOBUS interface '%s' failed.  "
			"Controller error message = '%s'", command_ptr,
					isobus->record->name, response );

					error_occurred = TRUE;
				} else {
					if ( isobus_flags & MXF_ISOBUS_DEBUG )
					{
						MX_DEBUG(-2,("%s: received "
						"response '%s' from '%s'",
							fname, response,
							isobus->record->name ));
					}
				}
			}
		}

		if ( error_occurred == FALSE ) {
			break;		/* Exit the for() loop. */
		}
	}

	if ( error_occurred ) {
		return mx_error( MXE_TIMED_OUT, fname,
	"The command '%s' to ISOBUS interface '%s' is still failing "
	"after %ld retries.  Giving up...", command_ptr,
				isobus->record->name,
				maximum_retries );
	} else {
		return MX_SUCCESSFUL_RESULT;
	}
}
コード例 #4
0
ファイル: d_icplus.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mxd_icplus_command( MX_ICPLUS *icplus,
			char *command,
			char *response,
			size_t response_buffer_length,
			int debug_flag )
{
	static const char fname[] = "mxd_icplus_command()";

	char c;
	int i, max_attempts;
	unsigned long sleep_ms, num_input_bytes_available;
	mx_status_type mx_status, mx_status2;

	if ( icplus == (MX_ICPLUS *) NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"NULL MX_ICPLUS pointer passed." );
	}
	if ( command == NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"NULL command buffer pointer passed." );
	}

	if ( debug_flag ) {
		MX_DEBUG(-2,("%s: sending '%s' to '%s'",
				fname, command, icplus->record->name ));
	}

	/* Send the command string. */

	mx_status = mx_rs232_putline( icplus->rs232_record, command, NULL, 0 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* The IC PLUS always sends an ACK character to acknowledge receipt
	 * of the LF terminator for the command that we just sent.  Even if
	 * we expect no other response, we must still read and discard this
	 * ACK character.
	 */

	mx_status = mx_rs232_getchar( icplus->rs232_record, &c, MXF_232_WAIT );

	if ( mx_status.code == MXE_NOT_READY ) {
		return mx_error( MXE_NOT_READY, fname,
		"No response received from %s amplifier '%s' "
		"for command '%s'.  Are you sure it is plugged in "
		"and turned on?",
			mx_get_driver_name( icplus->record ),
			icplus->record->name, command );
	}

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	if ( c != MX_ACK ) {
		(void) mx_rs232_discard_unread_input( icplus->rs232_record,
							MXD_ICPLUS_DEBUG );

		return mx_error( MXE_DEVICE_IO_ERROR, fname,
	"Did not receive an ACK acknowledgement character from "
	"%s interface '%s' in response to the command '%s'.  "
	"Instead, saw a %#x (%c) character.",
			mx_get_driver_name( icplus->record ),
			icplus->record->name, command, c, c );
	}

	/* If we expect a response, then read it in. */

	if ( response != NULL ) {
		mx_status = mx_rs232_getline( icplus->rs232_record,
					response, response_buffer_length,
					NULL, 0 );

		if ( debug_flag & (mx_status.code == MXE_SUCCESS) ) {
			MX_DEBUG(-2,("%s: received '%s' from '%s'",
				fname, response, icplus->record->name ));
		}
	} else {
		if ( debug_flag ) {
			MX_DEBUG(-2,("%s complete.", fname));
		}
	}

	/* If the IC PLUS echoes the command line back to us, then we must
	 * throw this away.
	 */

	if ( icplus->discard_echoed_command_line ) {
		max_attempts = 100;
		sleep_ms = 1;

		for ( i = 0; i < max_attempts; i++ ) {
			mx_status2 = mx_rs232_num_input_bytes_available(
						icplus->rs232_record,
						&num_input_bytes_available );

			if ( mx_status2.code != MXE_SUCCESS )
				break;

			if ( num_input_bytes_available > 0 )
				break;

			mx_msleep( sleep_ms );
		}

		if ( i >= max_attempts ) {
			mx_status = mx_error( MXE_TIMED_OUT, fname,
				"Timed out waiting for %s record '%s' to echo "
				"the command line '%s' back to us.",
					mx_get_driver_name( icplus->record ),
					icplus->record->name, command );
		}
		(void) mx_rs232_discard_unread_input(
					icplus->rs232_record, FALSE );
	}

	return mx_status;
}
コード例 #5
0
ファイル: d_sim980.c プロジェクト: nbeaver/mx-trunk
static mx_status_type
mxd_sim980_command( MX_SIM980 *sim980,
		char *command,
		char *response,
		size_t max_response_length,
		int debug_flag )
{
	static const char fname[] = "mxd_sim980_command()";

#if 0
	char esr_response[10];
	unsigned char esr_byte;
#endif
	mx_status_type mx_status;

	if ( command == (char *) NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"The command buffer pointer passed was NULL." );
	}

	/* Send the command. */

	if ( debug_flag ) {
		MX_DEBUG(-2,("%s: sending '%s' to '%s'",
			fname, command, sim980->record->name));
	}

	mx_status = mx_rs232_putline( sim980->port_record, command, NULL, 0 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	if ( response != (char *) NULL ) {
		/* If a response is expected, read back the response. */

		mx_status = mx_rs232_getline( sim980->port_record,
					response, max_response_length,
					NULL, 0 );

		if ( mx_status.code != MXE_SUCCESS )
			return mx_status;

		if ( debug_flag ) {
			MX_DEBUG(-2,("%s: received '%s' from '%s'",
			fname, response, sim980->record->name ));
		}
	}

	/* Check for errors in the previous command. */

#if 0

#if MXD_SIM980_ERROR_DEBUG
	MX_DEBUG(-2,("%s: sending '*ESR?' to '%s'",
		fname, sim980->record->name ));
#endif

	mx_status = mx_rs232_putline( sim980->port_record, "*ESR?", NULL, 0 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	mx_status = mx_rs232_getline( sim980->port_record,
					esr_response, sizeof(esr_response),
					NULL, 0 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

#if MXD_SIM980_ERROR_DEBUG
	MX_DEBUG(-2,("%s: received '%s' from '%s'",
		fname, esr_response, sim980->record->name ));
#endif

	esr_byte = atol( esr_response );

	if ( esr_byte & 0x20 ) {
		return mx_error( MXE_PROTOCOL_ERROR, fname,
		"Command error (CME) seen for command '%s' sent to '%s'.",
			command, sim980->record->name );
	} else
	if ( esr_byte & 0x10 ) {
		return mx_error( MXE_PROTOCOL_ERROR, fname,
		"Execution error (EXE) seen for command '%s' sent to '%s'.",
			command, sim980->record->name );
	} else
	if ( esr_byte & 0x08 ) {
		return mx_error( MXE_DEVICE_ACTION_FAILED, fname,
	    "Device dependent error (DDE) seen for command '%s' sent to '%s'.",
			command, sim980->record->name );
	} else
	if ( esr_byte & 0x02 ) {
		return mx_error( MXE_DEVICE_IO_ERROR, fname,
		"Input data lost (INP) for command '%s' sent to '%s'.",
			command, sim980->record->name );
	} else
	if ( esr_byte & 0x04 ) {
		return mx_error( MXE_DEVICE_IO_ERROR, fname,
		"Output data lost (QYE) for command '%s' sent to '%s'.",
			command, sim980->record->name );
	}

#endif /* 0 */

	return MX_SUCCESSFUL_RESULT;
}
コード例 #6
0
ファイル: d_src_mono.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mxd_src_mono_get_extended_status( MX_MOTOR *motor )
{
	static const char fname[] = "mxd_src_mono_get_extended_status()";

	MX_SRC_MONO *src_mono = NULL;
	unsigned long num_input_bytes_available;
	double current_position;
	int num_items;
	char response[200];
	mx_status_type mx_status;

	mx_status = mxd_src_mono_get_pointers( motor, &src_mono, NULL, fname );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

#if MXD_SRC_MONO_DEBUG
	MX_DEBUG(-2,("%s invoked for motor '%s'.", fname, motor->record->name));
	MX_DEBUG(-2,("%s: Starting src_mono->state = %d",
		fname, src_mono->state ));
#endif

	motor->status = MXSF_MTR_ERROR;

	switch( src_mono->state ) {
	case MXS_SRC_MONO_ERROR:
		/* Currently, all we can do is close our eyes, be optimistic
		 * and hope that any existing errors have gone away.  We do
		 * generate a warning about that though.
		 */

		src_mono->state = MXS_SRC_MONO_IDLE;

		mx_warning( "Resetting SRC mono error for motor '%s'.",
			motor->record->name );
		break;

	case MXS_SRC_MONO_TIMED_OUT:
		/* Generate a warning that we are ignoring a timeout. */

		src_mono->state = MXS_SRC_MONO_IDLE;

		mx_warning( "Ignoring timeout for motor '%s'.",
			motor->record->name );
		break;

	case MXS_SRC_MONO_ACTIVE:
		/* A move is currently supposed to be in progress.
		 * Has the move completed yet?  We check for this
		 * by seeing whether or not the SRC computer has
		 * sent us a message.
		 */

		mx_status = mx_rs232_num_input_bytes_available(
						src_mono->rs232_record,
						&num_input_bytes_available );

		if ( mx_status.code != MXE_SUCCESS ) {
			src_mono->state = MXS_SRC_MONO_ERROR;
			break;
		}

		if ( num_input_bytes_available == 0 ) {
			/* We have not been sent any new characters, so
			 * the move must not yet be complete.
			 */

			break;
		}

		/* Apparently the move has completed.  We now verify this
		 * by looking for a scan complete message.
		 */

		mx_status = mx_rs232_getline( src_mono->rs232_record,
						response, sizeof(response),
						NULL, MXD_SRC_MONO_DEBUG );

		if ( mx_status.code == MXE_TIMED_OUT ) {
			src_mono->state = MXS_SRC_MONO_TIMED_OUT;
		} else
		if ( mx_status.code != MXE_SUCCESS ) {
			src_mono->state = MXS_SRC_MONO_ERROR;
		} else {
			if ( strcmp( response, "OK-Scan Completed!" ) == 0 ) {
				src_mono->state = MXS_SRC_MONO_IDLE;
			} else {
				mx_status = mx_error(MXE_DEVICE_IO_ERROR, fname,
				"Received unexpected response '%s' from "
				"SRC monochromator '%s'.",
					response, motor->record->name );
			}
		}
		break;

	case MXS_SRC_MONO_IDLE:
		/* If the mono is idle, then there is nothing that we
		 * need to do at this point in the function.
		 */

		break;

	default:
		return mx_error( MXE_ILLEGAL_ARGUMENT, fname,
		"SRC mono '%s' is in illegal state %d.  "
		"This should never happen, but if it does, try restarting MX.",
			motor->record->name, src_mono->state );
	}

	if ( src_mono->state == MXS_SRC_MONO_ACTIVE ) {
		motor->status = MXSF_MTR_IS_BUSY;

		return MX_SUCCESSFUL_RESULT;
	}

	/* We should only get here if the monochromator is now idle.  
	 * It should now be safe to ask for the current position.
	 */

	mx_status = mx_rs232_putline( src_mono->rs232_record,
				"ENERGY", NULL, MXD_SRC_MONO_DEBUG );

	if ( mx_status.code != MXE_SUCCESS ) {
		src_mono->state = MXS_SRC_MONO_ERROR;
		return mx_status;
	}

	/* Now read back the motor position. */

	mx_status = mx_rs232_getline( src_mono->rs232_record,
					response, sizeof(response),
					NULL, MXD_SRC_MONO_DEBUG );

	if ( mx_status.code == MXE_TIMED_OUT ) {
		src_mono->state = MXS_SRC_MONO_TIMED_OUT;
		return mx_status;
	} else
	if ( mx_status.code != MXE_SUCCESS ) {
		src_mono->state = MXS_SRC_MONO_ERROR;
		return mx_status;
	}

	num_items = sscanf( response, "%lg", &current_position );

	if ( num_items != 1 ) {
		src_mono->state = MXS_SRC_MONO_ERROR;
		return mx_error( MXE_DEVICE_IO_ERROR, fname,
		"Did not find the position for SRC mono '%s' in the "
		"response '%s' to the 'ENERGY' command.",
			motor->record->name, response );
	}

	motor->raw_position.analog = current_position;

	motor->status = 0;

	return MX_SUCCESSFUL_RESULT;
}
コード例 #7
0
ファイル: i_numato_gpio.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mxi_numato_gpio_open( MX_RECORD *record )
{
	static const char fname[] = "mxi_numato_gpio_open()";

	MX_NUMATO_GPIO *numato_gpio = NULL;
	unsigned long flags;
	mx_bool_type debug_rs232;
	mx_status_type mx_status;

#if MXI_NUMATO_GPIO_DEBUG
	MX_DEBUG(-2,("%s invoked for record '%s'.", fname, record->name ));
#endif

	numato_gpio = (MX_NUMATO_GPIO *) record->record_type_struct;

	if ( numato_gpio == (MX_NUMATO_GPIO *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"MX_NUMATO_GPIO pointer for record '%s' is NULL.",
			record->name);
	}

	flags = numato_gpio->numato_gpio_flags;

	if ( flags & MXF_NUMATO_GPIO_DEBUG_RS232 ) {
		debug_rs232 = TRUE;
	} else {
		debug_rs232 = FALSE;
	}

	/* Make sure that the RS232 line terminators are set correctly.  The
	 * write terminator must be set to 0x0d, while the read terminators
	 * must be set to 0x3e0d (or '>\r').
	 */

#if 0
	{
		MX_RS232 *rs232 = (MX_RS232 *)
			numato_gpio->rs232_record->record_class_struct;

		rs232->read_terminators = 0x3e0d;
		rs232->write_terminators = 0x0d;

		mx_status = mx_rs232_convert_terminator_characters(
						numato_gpio->rs232_record );

		if ( mx_status.code != MXE_SUCCESS )
			return mx_status;
	}
#endif
	/* Send a <CR> to make sure that any partial commands or junk data
	 * have been discarded.
	 */

	mx_status = mx_rs232_putline( numato_gpio->rs232_record, "",
							NULL, debug_rs232 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	mx_msleep(1000);

	/* Discard any leftover bytes in the serial port. */

	mx_status = mx_rs232_discard_unwritten_output(
				numato_gpio->rs232_record, debug_rs232 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	mx_status = mx_rs232_discard_unread_input( numato_gpio->rs232_record,
								 debug_rs232 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* Read the version number of the Numato firmware. */

	mx_breakpoint();

	mx_status = mxi_numato_gpio_command( numato_gpio, "ver",
					numato_gpio->version,
					sizeof(numato_gpio->version),
					debug_rs232 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* Read the id number of the Numato device. */

	mx_status = mxi_numato_gpio_command( numato_gpio, "id",
					numato_gpio->id,
					sizeof(numato_gpio->id),
					debug_rs232 );

	return mx_status;
}
コード例 #8
0
ファイル: i_numato_gpio.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mxi_numato_gpio_command( MX_NUMATO_GPIO *numato_gpio,
				char *command,
				char *response,
				unsigned long max_response_length,
				mx_bool_type debug_rs232 )
{
	static const char fname[] = "mxi_numato_gpio_command()";

	MX_RECORD *rs232_record = NULL;
	MX_RS232 *rs232 = NULL;
	char local_buffer[80];
	size_t length;
	mx_status_type mx_status;

	if ( numato_gpio == (MX_NUMATO_GPIO *) NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"The MX_NUMATO_GPIO pointer passed was NULL." );
	}

	rs232_record = numato_gpio->rs232_record;

	if ( rs232_record == (MX_RECORD *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"The rs232_record pointer for Numato GPIO interface '%s' "
		"is NULL.", numato_gpio->record->name );
	}

	rs232 = (MX_RS232 *) rs232_record->record_class_struct;

	if ( rs232 == (MX_RS232 *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"The MX_RS232 pointer for RS232 record '%s' used "
		"by Numato GPIO interface '%s' is NULL.",
			rs232_record->name, numato_gpio->record->name );
	}

	/* The Numato GPIO device echoes back everything that we send to it.
	 * So we will need to readout and throw away that text.  We add 1
	 * to the end of the length of the text to include the echoed
	 * <CR> character.
	 */

#if 0
	length = strlen( command ) + 1;
#else
	length = strlen( command );
#endif

	if ( length > sizeof(local_buffer) ) {
		return mx_error( MXE_INTERFACE_IO_ERROR, fname,
		"The length (%ld) of the command '%s' (plus <CR>) sent to "
		"Numato GPIO device '%s' is longer than the length (%ld) of "
		"the local buffer used for reading out echoed responses.  "
		"You will need to either shorten the command or else "
		"increase the size of 'local_buffer' in the source code.  "
		"Numato commands are short, so you should never see "
		"this error message.",
			(long) length, command,
			numato_gpio->record->name,
			(long) sizeof(local_buffer) );
	}

	/* Now send the command. */

	if ( debug_rs232 ) {
		fprintf( stderr, "Sending '%s' to '%s'.\n",
			command, numato_gpio->record->name );
	}

	mx_status = mx_rs232_putline( rs232_record, command,
					NULL, debug_rs232 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* Discard the echoed text. */

	mx_status = mx_rs232_read( rs232_record,
				local_buffer, length,
				NULL, debug_rs232 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* Now get the response we are looking for. */

	mx_status = mx_rs232_getline_with_timeout( rs232_record,
						response, max_response_length,
						NULL, debug_rs232,
						rs232->timeout );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	return mx_status;
}
コード例 #9
0
ファイル: mx_umx.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mx_umx_command( MX_RECORD *umx_record,
		char *command,
		char *response,
		size_t max_response_length,
		mx_bool_type debug_flag )
{
	static const char fname[] = "mx_umx_command()";

	MX_UMX_SERVER *umx_server = NULL;
	MX_RECORD *rs232_record = NULL;
	char local_response_buffer[200];
	char *buffer_ptr = NULL;
	size_t buffer_length;
	mx_status_type mx_status;

	if ( umx_record == (MX_RECORD *) NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"The umx_record pointer passed was NULL." );
	}

	umx_server = (MX_UMX_SERVER *) umx_record->record_type_struct;

	if ( umx_server == (MX_UMX_SERVER *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"The MX_UMX_SERVER pointer for UMX server '%s' is NULL.",
			umx_record->name );
	}

	rs232_record = umx_server->rs232_record;

	if ( rs232_record == (MX_RECORD *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"The rs232_record pointer for UMX server '%s' is NULL.",
			umx_record->name );
	}

	if ( command != (char *) NULL ) {
		/* If requested, send a command. */

		if ( debug_flag ) {
			MX_DEBUG(-2,("%s: sending '%s' to '%s'.",
				fname, command, umx_record->name ));
		}

		mx_status = mx_rs232_putline( rs232_record, command,
					NULL, (unsigned long) debug_flag );

		if ( mx_status.code != MXE_SUCCESS )
			return mx_status;
	}

	if ( response != (char *) NULL ) {
		/* If requested, receive the response. */

		buffer_ptr = response;
		buffer_length = max_response_length;
	} else {
		/* If no response is expected, we still need to
		 * find out if the last command succeeded.
		 */

		buffer_ptr = local_response_buffer;
		buffer_length = sizeof(local_response_buffer);
	}

	while (TRUE) {
		/* We loop here just in case we need to retry the read.
		 * That can happen if we received a monitor callback '<'
		 * or a comment '#' line.
		 */

		mx_status = mx_rs232_getline( rs232_record,
					buffer_ptr, buffer_length,
					NULL, (unsigned long) debug_flag );

		if ( mx_status.code != MXE_SUCCESS )
			return mx_status;

		if ( debug_flag ) {
			MX_DEBUG(-2,("%s: received '%s' from '%s'.",
				fname, buffer_ptr, umx_record->name ));
		}

		switch( buffer_ptr[0] ) {
		case '$':	/* Success */

			/* If the caller expected a response, then the
			 * response is already in their buffer.  If it
			 * did not, then the response we got into the
			 * local buffer will be thrown away once we
			 * return.  In either case, we can just
			 * return now.
			 */

			return MX_SUCCESSFUL_RESULT;
			break;
		case '!':	/* Error */

			mx_status = mxp_umx_handle_error( rs232_record,
								buffer_ptr );
			break;
		case '<':	/* A monitor callback. */

			mx_status = mxp_umx_handle_monitor_callback(
						rs232_record, buffer_ptr );

			if ( mx_status.code != MXE_SUCCESS )
				return mx_status;

			/* If we get here, then we will retry the attempt
			 * to receive the response we were looking for. 
			 */

			continue; /* Go back to the top of the while () loop. */
			break;
		case '#':	/* We were sent a 'comment'. */

			/* Throw the rest of the line away and go back to the
			 * top of the while() loop to try again.
			 */

			continue; /* Go back to the top of the while () loop. */
			break;
		default:
			break;
		}

		/* If we get here, then we are done with processing
		 * responses for now and can return.
		 */

		return mx_status;
	}
}
コード例 #10
0
ファイル: i_spellman_df3.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mxi_spellman_df3_command( MX_SPELLMAN_DF3 *spellman_df3,
			char *command,
			char *response,
			size_t response_buffer_length,
			int debug_flag )
{
	static const char fname[] = "mxi_spellman_df3_command()";

	char local_command[100];
	unsigned long i, command_length, response_length;
	unsigned long command_checksum, expected_checksum, actual_checksum;
	char *checksum_ptr;
	mx_bool_type response_has_checksum;
	mx_status_type mx_status;

	if ( spellman_df3 == (MX_SPELLMAN_DF3 *) NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"The MX_SPELLMAN_DF3 pointer passed was NULL." );
	}

	if ( debug_flag ) {
		MX_DEBUG(-2,("%s: sending '%s' to '%s'",
			fname, command, spellman_df3->record->name ));
	}

	/* Compute the command checksum. */

	command_length = strlen(command);

	command_checksum = 0;

	for ( i = 0; i < command_length; i++ ) {
		command_checksum = command_checksum + command[i];
	}

	command_checksum = command_checksum % 256;

	/* Format the command to be sent to the power supply. */

	snprintf( local_command, sizeof(local_command),
		"%c%s%02lX", MX_CTRL_A, command, command_checksum );

#if 0
	{
		unsigned long local_command_length;
		int c;

		local_command_length = strlen(local_command);

		for ( i = 0; i < local_command_length; i++ ) {
			c = local_command[i];

			MX_DEBUG(-2,("%s: local_command[%lu] = %#x '%c'",
				fname, i, c, c));
		}
	}
#endif

	/* Send the command. */

	mx_status = mx_rs232_putline( spellman_df3->rs232_record,
					local_command, NULL, 0 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* Read the response. */

	mx_status = mx_rs232_getline( spellman_df3->rs232_record,
					response, response_buffer_length,
					NULL, 0 );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	response_length = strlen(response);

#if 0
	{
		int c;

		for ( i = 0; i < response_length; i++ ) {
			c = response[i];

			MX_DEBUG(-2,("%s: response[%lu] = %#x '%c'",
				fname, i, c, c));
		}
	}
#endif

	/* Should this response have a checksum? */

	switch( response[0] ) {
	case 'A':
		response_has_checksum = FALSE;
		break;
	case 'B':
	case 'E':
	case 'R':
		response_has_checksum = TRUE;
		break;
	default:
		return mx_error( MXE_INTERFACE_IO_ERROR, fname,
		"The response '%s' to the command '%s' sent to "
		"Spellman DF3/FF# '%s' starts with the unexpected "
		"character %X '%c'.",
			response, command, spellman_df3->record->name,
			response[0], response[0] );
		break;
	}

	if ( response_has_checksum ) {

		/* See if the two byte checksum is correct. */

		checksum_ptr = response + response_length - 2;

#if 0
		MX_DEBUG(-2,("%s: response '%s' checksum = '%s'",
			fname, response, checksum_ptr));
#endif

		/* The checksum leaves out the first character in the response
		 * as well as the two byte checksum at the end.
		 */

		expected_checksum = 0;

		for ( i = 1; i < (response_length - 2); i++ ) {
			expected_checksum = expected_checksum + response[i];
		}

		expected_checksum = expected_checksum % 256;

		/*---*/

		actual_checksum
			= 16 * mx_hex_char_to_unsigned_long( checksum_ptr[0] )
			     + mx_hex_char_to_unsigned_long( checksum_ptr[1] );

		if ( actual_checksum != expected_checksum ) {
			mx_warning( "The response '%s' to the command '%s' "
			"sent to Spellman DF3/FF3 '%s' had a checksum %#lX "
			"that did not match the expected checksum of %#lX.  "
			"Continuing anyway.",
				response, command, spellman_df3->record->name,
				actual_checksum, expected_checksum );
		}

		/* Strip off the two byte checksum. */

		*checksum_ptr = '\0';
	}

	if ( debug_flag ) {
		MX_DEBUG(-2,("%s: received '%s' from '%s'",
			fname, response, spellman_df3->record->name ));
	}

	/* If the response was not an error response, then we are done now. */

	if ( response[0] != 'E' ) {
		return MX_SUCCESSFUL_RESULT;
	}

	/* We received an error code.  Return an approprate error
	 * to the caller.
	 */

	switch( response[1] ) {
	case '1':
		return mx_error( MXE_NOT_VALID_FOR_CURRENT_STATE, fname,
		"Local Mode Error for '%s': A set command was attempted "
		"while the power supply was set to Local Mode.",
			spellman_df3->record->name );
		break;
	case '2':
		return mx_error( MXE_ILLEGAL_ARGUMENT, fname,
		"Undefined Command Code for '%s': The command character '%c' "
		"received was not an S, Q, or V.",
			spellman_df3->record->name, command[0] );
		break;
	case '3':
		return mx_error( MXE_INTERFACE_IO_ERROR, fname,
		"Checksum Error for '%s': The transmitted checksum received "
		"in the command packet did not match the checksum calculated "
		"on the received bytes.",
			spellman_df3->record->name );
		break;
	case '4':
		return mx_error( MXE_INTERFACE_IO_ERROR, fname,
		"Extra Byte(s) Received for '%s':  A byte other than the "
		"carriage return character was received in the last expected "
		"byte position of the command.",
			spellman_df3->record->name );
		break;
	case '5':
		return mx_error( MXE_CONFIGURATION_CONFLICT, fname,
		"Illegal Digital Control Byte in Set Command for '%s': "
		"Only one of the conditions 'X-ray On', 'X-ray Off', "
		"and 'Power Supply Reset' can be set in the digital control "
		"byte of the Set command at any one time.",
			spellman_df3->record->name );
		break;
	case '6':
		return mx_error( MXE_NOT_READY, fname,
		"Illegal Set Command Received While a Fault is Active "
		"for '%s': You must send a Power Supply Reset before "
		"sending any other commands.",
			spellman_df3->record->name );
		break;
	default:
		return mx_error( MXE_UNKNOWN_ERROR, fname,
		"Unrecognized error code '%c' was seen in the response '%s' "
		"to command '%s' for Spellman power supply '%s'.",
			response[1], response, command,
			spellman_df3->record->name );
		break;
	}

#if !defined(OS_SOLARIS)
	return MX_SUCCESSFUL_RESULT;
#endif
}
コード例 #11
0
ファイル: i_compumotor.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mxi_compumotor_command( MX_COMPUMOTOR_INTERFACE *compumotor_interface,
		char *command, char *response, size_t response_buffer_length,
		int command_flags )
{
	static const char fname[] = "mxi_compumotor_command()";

	MX_RS232 *rs232;
	unsigned long interface_flags;
	unsigned long sleep_ms, num_bytes_available;
	long num_command_attempts;
	long i, max_response_attempts;
	size_t command_length, response_length;
	char c;
	char echoed_command_string[200];
	mx_bool_type debug_flag, debug_getchar_flag;
	mx_status_type mx_status;
#if MXI_COMPUMOTOR_INTERFACE_DEBUG_TIMING	
	MX_HRT_RS232_TIMING command_timing, response_timing;
#endif

	debug_flag = FALSE;

	MX_DEBUG(2,("%s invoked.", fname));

	if ( compumotor_interface == NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"MX_COMPUMOTOR_INTERFACE pointer passed was NULL." );
	}
	if ( command == NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
		"'command' buffer pointer passed was NULL.  No command sent.");
	}
	if ( compumotor_interface->rs232_record == (MX_RECORD *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"The rs232_record pointer for record '%s' is NULL.",
			compumotor_interface->record->name );
	}

	rs232 = (MX_RS232 *)
			compumotor_interface->rs232_record->record_class_struct;

	if ( rs232 == (MX_RS232 *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"The MX_RS232 pointer for record '%s' used by '%s' is NULL.",
			compumotor_interface->rs232_record->name,
			compumotor_interface->record->name );
	}

	interface_flags = compumotor_interface->interface_flags;

	if ( interface_flags & MXF_COMPUMOTOR_ECHO_ON ) {

		command_length = strlen( command );

		if ( command_length > ( sizeof(echoed_command_string) - 1 ) ) {
			return mx_error( MXE_WOULD_EXCEED_LIMIT, fname,
	"Compumotor interface record '%s' has ECHO set to 1.  When ECHO is "
	"set to 1, commands are limited to a maximum of %ld characters, but "
	"the command string passed is %ld characters long.  command = '%s'",
			compumotor_interface->record->name,
			(long) sizeof( echoed_command_string ) - 1L,
			(long) command_length, command );
		}
	}

	if ( command_flags & MXI_COMPUMOTOR_INTERFACE_DEBUG ) {
		debug_flag = TRUE;
	} else
	if ( interface_flags & MXF_COMPUMOTOR_DEBUG_SERIAL ) {
	} else {
		debug_flag = FALSE;
	}

	if ( command_flags & MXF_COMPUMOTOR_NO_RECURSION ) {
		num_command_attempts = 1;
	} else
	if ( interface_flags & MXF_COMPUMOTOR_AUTOMATIC_RESYNCHRONIZE ) {
		num_command_attempts = 2;
	} else {
		num_command_attempts = 1;
	}

	if ( interface_flags & MXF_COMPUMOTOR_DEBUG_SERIAL_GETCHAR ) {
		if ( interface_flags & MXF_COMPUMOTOR_DEBUG_SERIAL ) {
			debug_getchar_flag = TRUE;
		} else
		if ( rs232->rs232_flags & MXF_232_DEBUG_SERIAL ) {
			debug_getchar_flag = TRUE;
		} else
		if ( rs232->rs232_flags & MXF_232_DEBUG_SERIAL_HEX ) {
			debug_getchar_flag = TRUE;
		} else {
			debug_getchar_flag = FALSE;
		}
	} else {
		debug_getchar_flag = FALSE;
	}

	/* Send the command string. */

	if ( debug_flag ) {
		MX_DEBUG(-2,("%s: sending '%s' to '%s'",
			fname, command, compumotor_interface->record->name));
	}

	while ( num_command_attempts > 0 ) {

	    num_command_attempts--;

#if MXI_COMPUMOTOR_INTERFACE_DEBUG_TIMING	
	    MX_HRT_RS232_START_COMMAND( command_timing, 2 + strlen(command) );
#endif

	    mx_status = mx_rs232_putline( compumotor_interface->rs232_record,
					command, NULL, 0 );

#if MXI_COMPUMOTOR_INTERFACE_DEBUG_TIMING
	    MX_HRT_RS232_END_COMMAND( command_timing );
#endif

	    if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

#if MXI_COMPUMOTOR_INTERFACE_DEBUG_TIMING
	MX_HRT_RS232_COMMAND_RESULTS( command_timing, command, fname );
#endif

	    if ( interface_flags & MXF_COMPUMOTOR_ECHO_ON ) {

		/* If the Compumotor is configured to echo commands,
		 * read the echoed command string.
		 */

#if MXI_COMPUMOTOR_INTERFACE_DEBUG_TIMING
		MX_HRT_RS232_START_RESPONSE( response_timing,
					compumotor_interface->rs232_record );
#endif

		mx_status = mx_rs232_getline(compumotor_interface->rs232_record,
					echoed_command_string,
					sizeof( echoed_command_string ) - 1L,
					NULL, 0 );

#if MXI_COMPUMOTOR_INTERFACE_DEBUG_TIMING
		MX_HRT_RS232_END_RESPONSE( response_timing,
					strlen(echoed_command_string) );

		MX_HRT_RS232_RESPONSE_RESULTS( response_timing,
					echoed_command_string, fname );
#endif

		if ( mx_status.code != MXE_SUCCESS )
			return mx_status;
	    }

	    /* Get the response, if one is expected. */

	    i = 0;

	    max_response_attempts = 1000;
	    sleep_ms = 1;

	    if ( response == NULL ) {

		/* If we are not checking for a response, then we have no
		 * way to tell whether or not the command succeeded.  That
		 * means that we have no justification for retrying a
		 * command, so we suppress command retries.
		 */

		num_command_attempts = 0;

	    } else {
		/* If we get here, a response is expected. */

#if MXI_COMPUMOTOR_INTERFACE_DEBUG_TIMING
#if 0
		MX_HRT_RS232_START_RESPONSE( response_timing,
					compumotor_interface->rs232_record );
#else
		MX_HRT_RS232_START_RESPONSE( response_timing, NULL );
#endif
#endif

		/* Any text sent by the Compumotor controller should
		 * be prefixed by an asterisk character, so to begin
		 * with, we try to read and discard characters until
		 * we see an asterisk.
		 */

		c = '\0';

		for ( i = 0; i < max_response_attempts; i++ ) {

			mx_status = mx_rs232_num_input_bytes_available(
					compumotor_interface->rs232_record,
					&num_bytes_available );

			if ( mx_status.code != MXE_SUCCESS )
				return mx_status;

			if ( num_bytes_available == 0 ) {
				/* Sleep and then go back to the top
				 * of the for() loop.
				 */

				mx_msleep(sleep_ms);
				continue;
			}

			mx_status = mx_rs232_getchar(
					compumotor_interface->rs232_record,
					&c, MXF_232_WAIT );

			if ( debug_getchar_flag ) {
				MX_DEBUG(-2,
				("%s: mx_rs232_getchar() = '%c' %#x",
					fname, c, c));
			}

			if ( mx_status.code != MXE_SUCCESS ) {
				response[0] = '\0';

				if ( debug_flag ) {
					MX_DEBUG(-2,
		("%s failed while waiting for an asterisk character from '%s'.",
				fname, compumotor_interface->record->name));
				}
				return mx_status;
			}

			/* Did we see the asterisk character? */

			if ( c != '*' ) {
				/* If not, sleep and then go back to
				 * the top of the for() loop.
				 */

				mx_msleep(sleep_ms);
				continue;	
			}

			/* Read in the Compumotor response. */

			mx_status = mx_rs232_getline(
					compumotor_interface->rs232_record,
					response, response_buffer_length,
					NULL, 0 );

			if ( mx_status.code == MXE_SUCCESS ) {
				break;		/* Exit the for() loop. */

			} else if ( mx_status.code != MXE_NOT_READY ) {
				MX_DEBUG(-2,
		("*** Exiting with status = %ld for Compumotor interface '%s'.",
			mx_status.code, compumotor_interface->record->name));

				return mx_status;
			}
			mx_msleep(sleep_ms);

		}   /* End of response attempt loop (i) */

		if ( i >= max_response_attempts ) {

		    if ( num_command_attempts > 0 ) {
			mx_warning( "Resynchronizing '%s'.",
					compumotor_interface->record->name );

			mx_status = mxi_compumotor_resynchronize(
					compumotor_interface->record );

			if ( mx_status.code != MXE_SUCCESS )
				return mx_status;

			mx_warning( "Resynchronization of '%s' complete.",
					compumotor_interface->record->name );
		    } else {
			mx_status = mx_rs232_discard_unread_input(
					compumotor_interface->rs232_record,
					debug_flag );

			if ( mx_status.code != MXE_SUCCESS ) {
				mx_error( MXE_INTERFACE_IO_ERROR, fname,
"Failed at attempt to discard unread characters in buffer for record '%s'",
					compumotor_interface->record->name );
			}

			return mx_error( MXE_TIMED_OUT, fname,
				"No response seen to '%s' command after "
				"%ld attempts to read from Compumotor "
				"interface '%s'.",
					command, max_response_attempts,
					compumotor_interface->record->name );
		    }
		} else {

		    /* Successfully got a response. */

		    num_command_attempts = 0;    /* No more attempts needed. */

		    /* Sometimes, the response string after the asterisk '*'
		     * character starts with a newline character.  If this
		     * has happened, strip off the leading newline.
		     */

		    if ( response[0] == MX_LF ) {
			response_length = strlen(response);

			memmove( response, response+1, response_length );
		    }

#if MXI_COMPUMOTOR_INTERFACE_DEBUG_TIMING
		    MX_HRT_RS232_END_RESPONSE( response_timing,
						strlen(response) );

		    MX_HRT_TIME_BETWEEN_MEASUREMENTS( command_timing,
						response_timing, fname );

		    MX_HRT_RS232_RESPONSE_RESULTS( response_timing,
						response, fname);
#endif

		    if ( debug_flag ) {
			MX_DEBUG(-2,("%s: received '%s' from '%s'",
				fname, response,
				compumotor_interface->record->name));
		    }
#if 0
		    {
			long j;

			response_length = strlen(response);

			for ( j = 0; j < response_length; j++ ) {
				MX_DEBUG(-2,("%s: response[%ld] = %#x '%c'",
				fname, j, response[j], response[j]));
			}
		    }
#endif
		}

	    } /* End of ( response != NULL ) block */

	} /* End of while() command attempt loop. */

	MX_DEBUG(2,("%s complete.", fname));

	return MX_SUCCESSFUL_RESULT;
}
コード例 #12
0
ファイル: i_compumotor.c プロジェクト: nbeaver/mx-trunk
MX_EXPORT mx_status_type
mxi_compumotor_open( MX_RECORD *record )
{
	static const char fname[] = "mxi_compumotor_open()";

	MX_COMPUMOTOR_INTERFACE *compumotor_interface;
	MX_RECORD *rs232_record;
	MX_RS232 *rs232;
	long i;
	unsigned long interface_flags;
	mx_status_type mx_status;

	if ( record == (MX_RECORD *) NULL ) {
		return mx_error( MXE_NULL_ARGUMENT, fname,
			"MX_RECORD pointer passed is NULL.");
	}

	compumotor_interface = (MX_COMPUMOTOR_INTERFACE *)
					(record->record_type_struct);

	if ( compumotor_interface == (MX_COMPUMOTOR_INTERFACE *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"MX_COMPUMOTOR_INTERFACE pointer for record '%s' is NULL.",
		record->name);
	}

	/* Are the line terminators set correctly? */

	rs232_record = compumotor_interface->rs232_record;

	if ( rs232_record == (MX_RECORD *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"rs232_record pointer for Compumotor interface '%s' is NULL.",
			record->name );
	}

	rs232 = (MX_RS232 *) rs232_record->record_class_struct;

	if ( rs232 == (MX_RS232 *) NULL ) {
		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"MX_RS232 pointer for RS-232 record '%s' is NULL.",
			compumotor_interface->rs232_record->name );
	}

#if 0
	if ( (rs232->read_terminators != 0x0d0a)
	  || (rs232->write_terminators != 0x0d0a) )
	{
		return mx_error( MXE_ILLEGAL_ARGUMENT, fname,
	"The Compumotor interface '%s' requires that the line terminators "
	"of RS-232 record '%s' be a carriage return followed by a line feed.  "
	"Instead saw read terminator %#x and write terminator %#x.",
		record->name, compumotor_interface->rs232_record->name,
		rs232->read_terminators, rs232->write_terminators );
	}
#endif

	/* If requested, attempt to automatically configure the parameter
	 * settings needed for correct communication handshaking with the
	 * Compumotor controller.  The most important ones are
	 *     EOT13,10,0
	 *     ERRLVL1
	 *     ECHO1
	 *     MA11111111
	 */

	interface_flags = compumotor_interface->interface_flags;

	if ( interface_flags & MXF_COMPUMOTOR_AUTO_COMMUNICATION_CONFIG ) {

#if MXI_COMPUMOTOR_INTERFACE_DEBUG
		MX_DEBUG(-2,
	  ("%s: Attempting automatic communication config for controller '%s'.",
			fname, record->name));
#endif

		/* Since we do not necessarily have correct handshaking set up
		 * yet, we send the first three commands in the blind.
		 */

		(void) mx_rs232_discard_unwritten_output( rs232_record,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		(void) mx_rs232_discard_unread_input( rs232_record,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		mx_status = mx_rs232_putline( rs232_record,
					"!EOT13,10,0", NULL,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		mx_status = mx_rs232_putline( rs232_record,
					"!ERRLVL1", NULL,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		mx_status = mx_rs232_putline( rs232_record,
					"!ECHO1", NULL,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		mx_status = mx_rs232_putline( rs232_record,
					"!MA11111111", NULL,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		if ( interface_flags & MXF_COMPUMOTOR_KILL_ON_STARTUP ) {
			mx_status = mx_rs232_putline( rs232_record,
					"!K", NULL,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		}

		/* If all went well, the controllers have been configured
		 * to handshake correctly with the MX driver.  We discard
		 * any responses from the controller so far.
		 */

		mx_msleep(100);

		mx_status = mx_rs232_discard_unread_input( rs232_record,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		if ( mx_status.code != MXE_SUCCESS )
			return mx_status;
	}

	/* If requested, send an '!ADDR1' command to automatically configure
	 * unit addresses.  This will not do the right thing for an RS-485
	 * multi-drop configuration, so it must be optional.
	 */

	if ( compumotor_interface->interface_flags
		& MXF_COMPUMOTOR_AUTO_ADDRESS_CONFIG )
	{
		/* If we are using autoaddressing, the controllers must be 
		 * numbered from 1 to num_controllers in the controller_number
		 * array for consistency.  If they are not, generate an
		 * error message.
		 */

		for ( i = 0; i < compumotor_interface->num_controllers; i++ ) {
			if ( compumotor_interface->controller_number[i] != i+1 )
			{
				return mx_error( MXE_ILLEGAL_ARGUMENT, fname,
"If MXF_COMPUMOTOR_AUTO_ADDRESS_CONFIG is set for record '%s', then the "
"controller addresses in the database must be in order from 1 to %ld.",
				compumotor_interface->record->name,
				compumotor_interface->num_controllers );
			}
		}

		/* Send the automatic configuration command. */

		(void) mx_rs232_discard_unwritten_output( rs232_record,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		mx_status = mx_rs232_putline( rs232_record,
					"!ADDR1", NULL,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

		switch( mx_status.code ) {
		case MXE_SUCCESS:
			break;
		case MXE_NOT_READY:
		case MXE_INTERFACE_IO_ERROR:
			return mx_error( MXE_INTERFACE_IO_ERROR, fname,
"Cannot set addresses for Compumotor interface '%s' on RS-232 port '%s'.  "
"Is it turned on?", record->name, compumotor_interface->rs232_record->name );
		default:
			return mx_status;
		}
	}

	/* Synchronize with the controllers. */

	mx_status = mxi_compumotor_resynchronize( record );

	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;

	/* If a startup program is defined, then run it. */

	if ( strlen( compumotor_interface->startup_program ) > 0 ) {
		mx_status = mxi_compumotor_run_program(
				compumotor_interface,
				"startup",
				compumotor_interface->startup_program );
	}

	return mx_status;
}