Esempio n. 1
0
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;
}
Esempio n. 2
0
MX_EXPORT mx_status_type
mxd_src_mono_open( MX_RECORD *record )
{
	static const char fname[] = "mxd_src_mono_open()";

	MX_MOTOR *motor = NULL;
	MX_SRC_MONO *src_mono = NULL;
	MX_RS232 *rs232 = NULL;
	mx_status_type mx_status;

	motor = (MX_MOTOR *) record->record_class_struct;

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

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

	/* Verify the RS-232 port parameters. */

#if 0
	mx_status = mx_rs232_verify_configuration( src_mono->rs232_record,
						9600, 8, 'N', 1, 'N',
						0x0d0a, 0x0d,
						rs232->timeout );
	if ( mx_status.code != MXE_SUCCESS )
		return mx_status;
#endif

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

	(void) mx_rs232_discard_unwritten_output( src_mono->rs232_record,
							MXD_SRC_MONO_DEBUG );

	mx_status = mx_rs232_discard_unread_input( src_mono->rs232_record,
							MXD_SRC_MONO_DEBUG );

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

	/* Verify that the connection is alive by asking for the
	 * current position.
	 */

	src_mono->state = MXS_SRC_MONO_IDLE;

	mx_status = mxd_src_mono_get_extended_status( motor );

	return mx_status;
}
Esempio n. 3
0
MX_EXPORT mx_status_type
mxi_compumotor_close( MX_RECORD *record )
{
	static const char fname[] = "mxi_compumotor_close()";

	MX_COMPUMOTOR_INTERFACE *compumotor_interface;
	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);
	}

	/* Get rid of any remaining characters in the input and output
	 * buffers and do it quietly.
	 */

	(void) mx_rs232_discard_unwritten_output(
				compumotor_interface->rs232_record, FALSE );

	mx_status = mx_rs232_discard_unread_input(
				compumotor_interface->rs232_record, FALSE );

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

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

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

	return mx_status;
}
Esempio n. 4
0
MX_EXPORT mx_status_type
mxd_icplus_resynchronize( MX_RECORD *record )
{
	static const char fname[] = "mxd_icplus_resynchronize()";

	MX_ICPLUS *icplus;
	char command[40];
	mx_status_type mx_status;

	icplus = NULL;

	mx_status = mxd_icplus_get_pointers( record, NULL, &icplus, fname );

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

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

	mx_status = mx_rs232_discard_unwritten_output( icplus->rs232_record,
							MXD_ICPLUS_DEBUG );

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

	mx_status = mx_rs232_discard_unread_input( icplus->rs232_record,
							MXD_ICPLUS_DEBUG );

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

	/* Reset the IC PLUS. */

	snprintf( command, sizeof(command), "*RST%ld", icplus->address );

	mx_status = mxd_icplus_command( icplus, command,
					NULL, 0, MXD_ICPLUS_DEBUG );

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

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

	return MX_SUCCESSFUL_RESULT;
}
Esempio n. 5
0
MX_EXPORT mx_status_type
mxi_isobus_open( MX_RECORD *record )
{
	static const char fname[] = "mxi_isobus_open()";

	MX_ISOBUS *isobus;
	MX_RECORD *interface_record;
	unsigned long isobus_flags, read_terminator;
	mx_status_type mx_status;

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

	isobus = (MX_ISOBUS *) record->record_type_struct;

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

	isobus_flags = isobus->isobus_flags;

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

	interface_record = isobus->isobus_interface.record;

	switch( interface_record->mx_class ) {
	case MXI_RS232:
		/* Verify that the RS-232 port has the right settings. */

		if ( isobus_flags & MXF_ISOBUS_READ_TERMINATOR_IS_LINEFEED ) {
			read_terminator = MX_LF;
		} else {
			read_terminator = MX_CR;
		}

		mx_status = mx_rs232_verify_configuration( interface_record,
				9600, 8, 'N', 1, 'N', read_terminator, 0x0d );

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

		/* Reinitialize the serial port. */

		mx_status = mx_resynchronize_record( interface_record );

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

		mx_msleep(1000);

		/* Discard any characters waiting to be sent or received. */

		mx_status = mx_rs232_discard_unwritten_output(
					interface_record, MXI_ISOBUS_DEBUG );

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

		mx_status = mx_rs232_discard_unread_input(
					interface_record, MXI_ISOBUS_DEBUG );

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

	case MXI_GPIB:
		/* GPIB does not require any initialization. */

		break;
	
	default:
		return mx_error( MXE_TYPE_MISMATCH, fname,
		"Only RS-232 and GPIB interfaces are supported for "
		"ISOBUS interface '%s'.  Interface record '%s' is "
		"of unsupported type '%s'.",
			record->name, interface_record->name,
			mx_get_driver_name( interface_record ) );

		break;
	}

	return MX_SUCCESSFUL_RESULT;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
MX_EXPORT mx_status_type
mxd_icplus_open( MX_RECORD *record )
{
	static const char fname[] = "mxd_icplus_open()";

	MX_AMPLIFIER *amplifier;
	MX_ICPLUS *icplus;
	MX_RS232 *rs232;
	char command[40];
	char response[80];
	int timed_out;
	unsigned long i, max_attempts, wait_ms, num_input_bytes_available;
	mx_status_type mx_status;

	amplifier = NULL;
	icplus = NULL;

	mx_status = mxd_icplus_get_pointers( record,
					&amplifier, &icplus, fname );

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

	mx_status = mx_rs232_get_pointers( icplus->rs232_record,
						&rs232, NULL, fname );

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

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

	/* The ICPLUS driver does not use the QBPM flags. */

	if ( record->mx_type == MXT_AMP_ICPLUS ) {
		icplus->qbpm_flags = 0;
	}

	/* See if the serial port is configured correctly. */

	if( record->mx_type == MXT_AMP_ICPLUS ) {
		mx_status = mx_rs232_verify_configuration( icplus->rs232_record,
					9600, 8, 'N', 1, 'N', 0x0a, 0x0a,
					rs232->timeout );
	} else {
		mx_status = mx_rs232_verify_configuration( icplus->rs232_record,
					19200, 8, 'N', 1, 'N', 0x0a, 0x0a,
					rs232->timeout );
	}

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

	/* Throw away any leftover characters. */

	mx_status = mx_rs232_discard_unwritten_output( icplus->rs232_record,
							MXD_ICPLUS_DEBUG );

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

	mx_status = mx_rs232_discard_unread_input( icplus->rs232_record,
							MXD_ICPLUS_DEBUG );

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

	/* If the RS-232 port does not have a timeout specified, set
	 * the timeout to 1 second.
	 */

	if ( rs232->timeout < 0.0 ) {
		rs232->timeout = 1.0;

		MX_DEBUG( 2,("%s: forcing the timeout to 1 second.", fname));
	}

	/* See if the IC PLUS is available by trying to read
	 * the input current.
	 */

	if ( icplus->record->mx_type == MXT_AMP_ICPLUS ) {
		snprintf( command, sizeof(command),
				":READ%ld:CURR?", icplus->address );
	} else {
		snprintf( command, sizeof(command),
				":READ%ld:CURR1?", icplus->address );
	}

	wait_ms = 100;
	max_attempts = 5;
	timed_out = FALSE;

	for ( i = 0; i < max_attempts; i++ ) {
		mx_status = mxd_icplus_command( icplus, command,
					response, sizeof response,
					MXD_ICPLUS_DEBUG );

		switch( mx_status.code ) {
		case MXE_SUCCESS:
			timed_out = FALSE;
			break;
		case MXE_NOT_READY:
		case MXE_TIMED_OUT:
			timed_out = TRUE;
			break;
		default:
			return mx_status;
			break;
		}

		if ( timed_out == FALSE )
			break;			/* Exit the for() loop. */

		/* Resynchronize the serial port.  This will cause
		 * the serial port to be closed and then reopened.
		 */

#if MXD_ICPLUS_DEBUG
		MX_DEBUG(-2,("%s: resynchronizing the serial port.", fname));
#endif

		mx_status = mx_resynchronize_record( icplus->rs232_record );

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

		mx_msleep( wait_ms );
	}

	/* If there are still characters available from the RS-232 port,
	 * then the serial port is echoing back part of the transmitted
	 * command.  This means that the RS-232 cable is incorrectly
	 * wired, but we will attempt to continue anyway.
	 */

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

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

	if ( num_input_bytes_available > 0 ) {
		icplus->discard_echoed_command_line = TRUE;

		(void) mx_rs232_discard_unread_input( icplus->rs232_record,
						      	FALSE );

		mx_warning(
	"Some or all of the command string transmitted to '%s' device '%s' "
	"was echoed back to the serial port.  This means that the RS-232 "
	"cable is incorrectly wired, but we will attempt to continue by "
	"discarding the echoed characters.  However, this slows down the "
	"driver, so it would be better to fix the wiring.",
			mx_get_driver_name( icplus->record ), record->name );

	}

	/* Set the gain, offset, and peaking time. */

	mx_status = mx_amplifier_set_gain( record, amplifier->gain );

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

	mx_status = mx_amplifier_set_offset( record, amplifier->offset );

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

	mx_status = mx_amplifier_set_time_constant( record,
						amplifier->time_constant );

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

	/* If this is a QBPM controller, set the initial averaging. */

	if ( record->mx_type == MXT_AMP_QBPM ) {
		if ( icplus->default_averaging > 100 ) {
			return mx_error( MXE_WOULD_EXCEED_LIMIT, fname,
		"The requested averaging size of %ld for record '%s' is "
		"outside the allowed range of 1 to 100.",
				icplus->default_averaging, record->name );
		} else
		if ( icplus->default_averaging >= 1 ) {
			snprintf( command, sizeof(command),
					":READ%ld:AVGCURR %ld",
					icplus->address,
					icplus->default_averaging );
		} else
		if ( icplus->default_averaging > -1 ) {
			snprintf( command, sizeof(command),
					":READ%ld:SINGLE",
					icplus->address );
		} else
		if ( icplus->default_averaging >= -100 ) {
			snprintf( command, sizeof(command),
					":READ%ld:WDWCURR %ld",
					icplus->address,
					-(icplus->default_averaging) );
		} else {
			return mx_error( MXE_WOULD_EXCEED_LIMIT, fname,
		"The requested moving average size of %ld for record '%s' is "
		"outside the allowed range of -1 to -100.",
				icplus->default_averaging, record->name );
		}

		mx_status = mxd_icplus_command( icplus, command, NULL, 0,
							MXD_ICPLUS_DEBUG );
	}

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

	return MX_SUCCESSFUL_RESULT;
}
Esempio n. 8
0
MX_EXPORT mx_status_type
mxd_sim980_open( MX_RECORD *record )
{
	static const char fname[] = "mxd_sim980_open()";

	MX_ANALOG_INPUT *ainput;
	MX_SIM980 *sim980 = NULL;
	char response[100];
	char copy_of_response[100];
	int argc, num_items;
	char **argv;
	mx_status_type mx_status;

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

	ainput = (MX_ANALOG_INPUT *) record->record_class_struct;

	mx_status = mxd_sim980_get_pointers( ainput, &sim980, fname );

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

	/* Discard any outstanding characters. */

	mx_status = mx_rs232_discard_unwritten_output( sim980->port_record,
							MXD_SIM980_DEBUG );

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

	mx_status = mx_rs232_discard_unread_input( sim980->port_record,
							MXD_SIM980_DEBUG );

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

	/* Reset the communication interface by sending a break signal. */

#if MXD_SIM980_DEBUG
	MX_DEBUG(-2,("%s: sending a break signal to '%s'.",
				fname, record->name ));
#endif

	mx_status = mx_rs232_send_break( sim980->port_record );

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

	/* Verify that we are connected to a SIM980 analog PID controller. */

	mx_status = mxd_sim980_command( sim980, "*IDN?",
					response, sizeof(response),
					MXD_SIM980_DEBUG );

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

	strlcpy( copy_of_response, response, sizeof(copy_of_response) );

	mx_string_split( copy_of_response, ",", &argc, &argv );

	if ( argc != 4 ) {
		free( argv );

		return mx_error( MXE_DEVICE_IO_ERROR, fname,
		"Did not find 4 tokens in the response '%s' to "
		"the *IDN? command sent to '%s'.",
			response, record->name );
	}
	if ( strcmp( argv[0], "Stanford_Research_Systems" ) != 0 ) {
		free( argv );

		return mx_error( MXE_ILLEGAL_ARGUMENT, fname,
		"Controller '%s' is not a Stanford Research Systems device.  "
		"The response to '*IDN?' was '%s'.",
			record->name, response );
	}
	if ( strcmp( argv[1], "SIM980" ) != 0 ) {
		free( argv );

		return mx_error( MXE_ILLEGAL_ARGUMENT, fname,
		"Device '%s' is not a SIM980 analog PID controller.  "
		"The response to '*IDN?' was '%s'.",
			record->name, response );
	}

	/* Get the version number. */

	num_items = sscanf( argv[3], "ver%lf", &(sim980->version) );

	if ( num_items != 1 ) {
		mx_status = mx_error( MXE_DEVICE_IO_ERROR, fname,
		"Did not find the SIM980 version number in the token '%s' "
		"contained in the response '%s' to '*IDN?' by controller '%s'.",
			argv[3], response, record->name );

		free( argv );

		return mx_status;
	}

	return mx_status;
}
Esempio n. 9
0
MX_EXPORT mx_status_type
mxi_keithley2000_open( MX_RECORD *record )
{
	static const char fname[] = "mxi_keithley2000_open()";

	static char idcode[] = "KEITHLEY INSTRUMENTS INC.,MODEL 20";

	MX_KEITHLEY2000 *keithley2000 = NULL;
	MX_INTERFACE *interface = NULL;
	char response[160];
	mx_status_type mx_status;

	mx_status = mxi_keithley2000_get_pointers( record,
			&keithley2000, &interface, fname );

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

	switch ( interface->record->mx_class ) {
	case MXI_RS232:
		mx_status = mx_rs232_discard_unread_input( interface->record,
							KEITHLEY2000_DEBUG );

		if ( mx_status.code != MXE_SUCCESS )
			return mx_status;
		break;
	case MXI_GPIB:
		mx_status = mx_gpib_open_device( interface->record,
						interface->address );

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

		mx_status = mx_gpib_selective_device_clear( interface->record,
							interface->address );

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

#if 0
		mx_status = mx_gpib_remote_enable( interface->record,
							interface->address );

		if ( mx_status.code != MXE_SUCCESS )
			return mx_status;
#endif
		break;
	default:
		return mx_error( MXE_TYPE_MISMATCH, fname,
		"Interface '%s' for Keithley 2000 record '%s' "
		"is not an RS-232 or GPIB record.",
			interface->record->name, record->name );
	}

	/**** Find out what kind of controller this is. ****/

	/* Need to avoid mxi_keithley_command() at this stage,
	 * since that function automatically calls *STB?, which
	 * we probably do not want when we are trying to establish
	 * what kind of module this is.
	 */

	mx_status = mxi_keithley_putline( record, interface, "*IDN?",
						KEITHLEY2000_DEBUG );

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

	mx_status = mxi_keithley_getline( record, interface,
						response, sizeof(response),
						KEITHLEY2000_DEBUG );

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

	MX_DEBUG( 2,("%s: *IDN? response for record '%s' is '%s'",
			fname, record->name, response));

	if ( strncmp( response, idcode, strlen(idcode) ) != 0 ) {
		return mx_error( MXE_TYPE_MISMATCH, fname,
	"The controller '%s' is not a Keithley 2000 series multimeter.  "
	"Its response to an identification query command '*IDN?' was '%s'.",
			record->name, response );
	}

	/* Clear the 2000 Error Queue. */

	mx_status = mxi_keithley_command( record, interface, "SYST:CLE",
						NULL, 0, KEITHLEY2000_DEBUG );

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

	keithley2000->last_measurement_type = MXT_KEITHLEY2000_UNKNOWN;

	return mx_status;
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
MX_EXPORT mx_status_type
mxi_spellman_df3_open( MX_RECORD *record )
{
	static const char fname[] = "mxi_spellman_df3_open()";

	MX_SPELLMAN_DF3 *spellman_df3;
	char response[40];
	int num_items;
	unsigned long software_version;
	mx_status_type mx_status;

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

	spellman_df3 = (MX_SPELLMAN_DF3 *) record->record_type_struct;

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

	/* Compute the query command interval in clock ticks. */

	if ( spellman_df3->query_interval > 0 ) {
		spellman_df3->ticks_per_query =
	    mx_convert_seconds_to_clock_ticks( spellman_df3->query_interval );

		spellman_df3->next_query_tick = mx_current_clock_tick();
	}

	/* Clear out any existing trash from the RS-232 line. */

	mx_status = mx_rs232_discard_unread_input( spellman_df3->rs232_record,
						MXI_SPELLMAN_DF3_DEBUG );

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

	/* Verify that the Spellman power supply is present by asking
	 * for its software version.
	 */

	mx_status = mxi_spellman_df3_command( spellman_df3, "V",
						response, sizeof(response),
						MXI_SPELLMAN_DF3_DEBUG );

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

	num_items = sscanf( response, "B%lu", &software_version );

	if ( num_items != 1 ) {
		return mx_error( MXE_INTERFACE_IO_ERROR, fname,
		"The response '%s' to the 'V' command for "
		"Spellman DF3/FF3 '%s' was not recognizable.",
			response, record->name );
	}

#if MXI_SPELLMAN_DF3_DEBUG
	MX_DEBUG(-2,("%s: Spellman DF3/FF3 '%s' software version = %lu",
			fname, record->name, software_version ));
#endif

	/* Initialize the monitor arrays by doing a query command. */

	mx_status = mxi_spellman_df3_query_command( spellman_df3 );

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

	/* Copy the voltage and current monitor values to the control array.
	 *
	 * NOTE: The copied values must be rescaled since control values
	 * run from 0 to 0xFFF, while monitor values run from 0 to 0x3FF.
	 * This basically means that the monitor values must be multiplied
	 * by 4.
	 */

	spellman_df3->analog_control[MXF_SPELLMAN_DF3_VOLTAGE_CONTROL] =
	  4 * spellman_df3->analog_monitor[MXF_SPELLMAN_DF3_VOLTAGE_MONITOR];

	spellman_df3->analog_control[MXF_SPELLMAN_DF3_CURRENT_CONTROL] =
	  4 * spellman_df3->analog_monitor[MXF_SPELLMAN_DF3_CURRENT_MONITOR];

	/* Copy in the default power and filament current limits. */

	spellman_df3->analog_control[MXF_SPELLMAN_DF3_POWER_LIMIT]
		= (int) spellman_df3->default_power_limit;

	spellman_df3->analog_control[MXF_SPELLMAN_DF3_FILAMENT_CURRENT_LIMIT]
		= (int) spellman_df3->default_filament_current_limit;

	/* Set all of the digital control fields to 0. */

	memset( spellman_df3->digital_control, 0,
		sizeof(spellman_df3->digital_control) );

	return MX_SUCCESSFUL_RESULT;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
MX_EXPORT mx_status_type
mxi_compumotor_resynchronize( MX_RECORD *record )
{
	static const char fname[] = "mxi_compumotor_resynchronize()";

	MX_COMPUMOTOR_INTERFACE *compumotor_interface = NULL;
	char command[80], response[80];
	char version_string[80], type_string[80];
	long i, j;
	int num_items, command_flags;
	mx_status_type mx_status;

	mx_status = mxi_compumotor_get_pointers( record,
				&compumotor_interface, fname );

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

	/* Throw away any pending input and output on the 
	 * Compumotor RS-232 port.
	 */

	mx_status = mx_rs232_discard_unwritten_output(
					compumotor_interface->rs232_record,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

	switch( mx_status.code ) {
	case MXE_SUCCESS:
	case MXE_UNSUPPORTED:
		break;		/* Continue on. */
	default:
		return mx_status;
	}

	mx_status = mx_rs232_discard_unread_input(
					compumotor_interface->rs232_record,
					MXI_COMPUMOTOR_INTERFACE_DEBUG);

	/* Verify that each of the controllers are there by asking them
	 * for their revision number.
	 */

	command_flags = MXI_COMPUMOTOR_INTERFACE_DEBUG
			| MXF_COMPUMOTOR_NO_RECURSION;

	for ( i = 0; i < compumotor_interface->num_controllers; i++ ) {

		snprintf( command, sizeof(command), "%ld_!TREV",
				compumotor_interface->controller_number[i] );
	
		mx_status = mxi_compumotor_command( compumotor_interface,
				command, response, sizeof response,
				command_flags );

		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 communicate with Compumotor controller %ld on RS-232 port '%s'.  "
"Is it turned on?", i+1, compumotor_interface->rs232_record->name );
			break;
		default:
			return mx_status;
			break;
		}

		/* Attempt to determine the model of each type of
		 * controller.  The effectiveness of this logic is
		 * limited by the fact that I only have access to
		 * 6K and Zeta 6104 controllers.  (W. Lavender)
		 */

		compumotor_interface->controller_type[i]
						= MXT_COMPUMOTOR_UNKNOWN;

		num_items = sscanf( response, "%s %s",
					version_string, type_string );

		if ( num_items == 1 ) {
			compumotor_interface->controller_type[i]
						= MXT_COMPUMOTOR_6000_SERIES;

		} else if ( num_items == 2 ) {
			if ( strcmp( type_string, "6K" ) == 0 ) {

				compumotor_interface->controller_type[i]
						= MXT_COMPUMOTOR_6K;
			} else
			if ( strcmp( type_string, "ZETA6000" ) == 0 ) {

				compumotor_interface->controller_type[i]
						= MXT_COMPUMOTOR_ZETA_6000;
			} else
			if ( strcmp( type_string, "6104" ) == 0 ) {

				compumotor_interface->controller_type[i]
						= MXT_COMPUMOTOR_ZETA_6000;
			} else {
				compumotor_interface->controller_type[i]
						= MXT_COMPUMOTOR_6000_SERIES;
			}
		}

		if ( compumotor_interface->controller_type[i]
				== MXT_COMPUMOTOR_UNKNOWN )
		{
			(void) mx_error( MXE_UNPARSEABLE_STRING, fname,
	"Compumotor interface '%s' had an unrecognized response to "
	"the TREV command.  TREV response = '%s'",
			record->name, response );
		}
	}

	/* Try to enable all of the axes for each controller. */

	for ( i = 0; i < compumotor_interface->num_controllers; i++ ) {

		snprintf( command, sizeof(command), "%ld_!DRIVE",
				compumotor_interface->controller_number[i] );

		for ( j = 0; j < compumotor_interface->num_axes[i]; j++ ) {

			strlcat( command, "1", sizeof(command) );
		}

		(void) mxi_compumotor_command( compumotor_interface,
					command, NULL, 0,
					command_flags );
	}

	/* Discard any unread output from the controller. */

	mx_msleep(100);

	mx_status = mx_rs232_discard_unread_input(
					compumotor_interface->rs232_record,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

	return mx_status;
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
static mx_status_type
mxi_compumotor_run_program( MX_COMPUMOTOR_INTERFACE *compumotor_interface,
				char *program_type,
				char *program_filename )
{
	static const char fname[] = "mxi_compumotor_run_program()";

	int saved_errno;
	FILE *program_file;
	char program_line[200];
	char *ptr;
	long i, length;
	mx_bool_type suppress_comments;
	mx_status_type mx_status;

	if ( compumotor_interface->interface_flags
			& MXF_COMPUMOTOR_SUPPRESS_COMMENTS )
	{
		suppress_comments = TRUE;
	} else {
		suppress_comments = FALSE;
	}

	/* Try to open the startup program file. */

	program_file = mx_cfn_fopen( MX_CFN_CONFIG, program_filename, "r" );

	if ( program_file == ( FILE * ) NULL ) {
		saved_errno = errno;

		return mx_error( MXE_FILE_IO_ERROR, fname,
		"The attempt by record '%s' to open %s program "
		"file '%s' failed.  Errno = %d, error message = '%s'.",
			compumotor_interface->record->name,
			program_type, program_filename,
			saved_errno, strerror(saved_errno) );
	}

	/* Read the startup program one line at a time
	 * and send it to the Compumotor controller.
	 */

	while (1) {
		mx_fgets( program_line, sizeof(program_line),
						program_file );

		if ( feof(program_file) ) {
			fclose( program_file );
			program_file = NULL;
			break;		/* Exit the while() loop. */
		} else
		if ( ferror(program_file) ) {
			saved_errno = errno;
			fclose( program_file );

			return mx_error( MXE_FILE_IO_ERROR, fname,
			"An error occurred while reading from "
			"%s program file '%s' for record '%s'.  "
			"Errno = %d, error message = '%s'.",
				program_type, program_filename,
				compumotor_interface->record->name,
				saved_errno, strerror(saved_errno) );
		}

		if ( suppress_comments ) {
			/* Look for the comment character ';'. */

			ptr = strchr( program_line, ';' );

			if ( ptr != NULL ) {
				*ptr = '\0';
			}

			/* Suppress trailing spaces or tabs. */

			length = strlen( program_line );

			for ( i = length-1; i >= 0; i-- ) {

				if ( program_line[i] == ' ' ) {
					program_line[i] = '\0';
				} else
				if ( program_line[i] == '\t' ) {
					program_line[i] = '\0';
				} else {
					break;	/* Exit the for() loop. */
				}
			}

			if ( strlen( program_line ) == 0 ) {
				/* If we have an empty line, do not send it
				 * to the controller and go back to the top
				 * of the while() loop.
				 */

				continue;
			}
		}

		mx_status = mxi_compumotor_command(
				compumotor_interface,
				program_line,
				NULL, 0,
				MXI_COMPUMOTOR_INTERFACE_DEBUG );

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

	/* This should never happen, but we check anyway. */

	if ( program_file != NULL ) {
		fclose( program_file );

		return mx_error( MXE_CORRUPT_DATA_STRUCTURE, fname,
		"The FILE pointer for file '%s' used by record '%s' "
		"was not NULL at a time when the file should "
		"already be closed.",
			program_filename,
			compumotor_interface->record->name );
	}

	/* If the commands we sent generated any output,
	 * we throw the output away now.
	 */

	mx_msleep(100);

	mx_status = mx_rs232_discard_unread_input(
					compumotor_interface->rs232_record,
					MXI_COMPUMOTOR_INTERFACE_DEBUG );

	return mx_status;
}