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; } }
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; }
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", ¤t_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; }
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, &lifier, &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; }
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; }