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; }
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; }
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; }
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 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; } }
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 }
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; }