Exemple #1
0
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;
}
Exemple #2
0
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;
	}
}
Exemple #3
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;
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #6
0
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;
	}
}
Exemple #7
0
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
}
Exemple #8
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;
}