static mx_status_type child_function( MX_THREAD *thread, void *args ) { mx_status_type mx_status; fprintf( stderr, "Child: Child thread starting.\n" ); fprintf( stderr, "Child: Installing stop request handler.\n" ); mx_status = mx_thread_set_stop_request_handler( thread, stop_request_handler, NULL ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; while(1) { fprintf( stderr, "Child: Checking for stop request.\n" ); mx_status = mx_thread_check_for_stop_request( thread ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; mx_msleep(500); } /* We should never get here. */ }
int main( int argc, char *argv[] ) { MX_THREAD *child_thread; long thread_exit_status; mx_status_type mx_status; fprintf( stderr, "Parent: Creating child thread.\n" ); mx_status = mx_thread_create( &child_thread, child_function, NULL ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); fprintf( stderr, "Parent: Hit any key to stop the child thread.\n" ); while(1) { if ( mx_kbhit() ) { break; /* Exit the while() loop. */ } mx_msleep(100); } fprintf( stderr, "Parent: Asking the child thread to stop.\n" ); mx_status = mx_thread_stop( child_thread ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); fprintf( stderr, "Parent: Waiting for the child thread to stop.\n" ); mx_status = mx_thread_wait( child_thread, &thread_exit_status, MX_THREAD_INFINITE_WAIT ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); fprintf( stderr, "Parent: Child thread exit status = %ld.\n", thread_exit_status ); fprintf( stderr, "Parent: Freeing child data structures.\n" ); mx_status = mx_thread_free_data_structures( child_thread ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); /* Announce to the user that the test is over. */ fprintf( stderr, "Parent: Thread test completed successfully.\n" ); exit(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; }
MX_EXPORT mx_status_type mx_bluice_wait_for_device_pointer_initialization( MX_BLUICE_SERVER *bluice_server, char *name, long bluice_foreign_type, MX_BLUICE_FOREIGN_DEVICE ***foreign_device_array_ptr, long *num_foreign_devices_ptr, MX_BLUICE_FOREIGN_DEVICE **foreign_device_ptr, double timeout_in_seconds ) { static const char fname[] = "mx_bluice_wait_for_device_pointer_initialization()"; unsigned long i, wait_ms, max_attempts; mx_status_type mx_status; /* Wait for the Blu-Ice server thread to assign a value to the pointer. */ wait_ms = 100; max_attempts = mx_round( (1000.0 * timeout_in_seconds) / (double) wait_ms ); for ( i = 0; i < max_attempts; i++ ) { mx_status = mx_bluice_device_pointer_fn( bluice_server, name, foreign_device_array_ptr, num_foreign_devices_ptr, FALSE, foreign_device_ptr ); if ( mx_status.code == MXE_NOT_FOUND ) { mx_msleep( wait_ms ); } else { if ( mx_status.code != MXE_SUCCESS ) return mx_status; if ( (*foreign_device_ptr) == NULL ) { mx_msleep( wait_ms ); } else { break; /* Exit the for() loop. */ } } } if ( i >= max_attempts ) { return mx_error( MXE_TIMED_OUT, fname, "Timed out after waiting %g seconds for Blu-Ice server '%s' " "to initialize Blu-Ice device '%s'.", timeout_in_seconds, bluice_server->record->name, name ); } if ( bluice_foreign_type != (*foreign_device_ptr)->foreign_type ) { return mx_error( MXE_TYPE_MISMATCH, fname, "The type (%ld) of Blu-Ice server device '%s' does not " "match the expected type of %ld. Perhaps you have specified " "an incorrect device name?", (*foreign_device_ptr)->foreign_type, name, bluice_foreign_type ); } return MX_SUCCESSFUL_RESULT; }
MX_EXPORT mx_status_type mx_bluice_receive_message( MX_RECORD *bluice_server_record, char *data_buffer, long data_buffer_length, long *actual_data_length, double timeout_in_seconds ) { static const char fname[] = "mx_bluice_receive_message()"; MX_BLUICE_SERVER *bluice_server; MX_SOCKET *bluice_server_socket; char message_header[MX_BLUICE_MSGHDR_LENGTH+1]; long text_data_length, binary_data_length, total_data_length; long maximum_length; size_t actual_bytes_received; long num_bytes_available; unsigned long i, wait_ms, max_attempts; char *data_pointer; mx_status_type mx_status; bluice_server = NULL; bluice_server_socket = NULL; mx_status = mx_bluice_get_pointers( bluice_server_record, &bluice_server, &bluice_server_socket, fname ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* Wait for a new message to come in. * * A negative timeout means wait forever, so we only need to loop * if the timeout is >= 0. */ if ( timeout_in_seconds >= 0.0 ) { wait_ms = 10; max_attempts = mx_round((1000.0 * timeout_in_seconds) / (double) wait_ms); for ( i = 0; i < max_attempts; i++ ) { mx_status = mx_socket_num_input_bytes_available( bluice_server->socket, &num_bytes_available ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; if ( num_bytes_available != 0 ) { break; /* Exit the for() loop. */ } mx_msleep( wait_ms ); } if ( i >= max_attempts ) { return mx_error( MXE_TIMED_OUT, fname, "Timed out after %g seconds of waiting for " "Blu-Ice server '%s' to send a message.", timeout_in_seconds, bluice_server_record->name ); } } /* Read in the header from the Blu-Ice server. */ mx_status = mx_socket_receive( bluice_server_socket, message_header, MX_BLUICE_MSGHDR_LENGTH, NULL, NULL, 0, 0 ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* Make sure the message header is null terminated. */ message_header[MX_BLUICE_MSGHDR_LENGTH-1] = '\0'; /* Get the length of the binary data. */ binary_data_length = atol( &message_header[MX_BLUICE_MSGHDR_BINARY] ); if ( binary_data_length != 0 ) { mx_warning( "The binary data length for the message being " "received from Blu-Ice server '%s' is not 0. " "Instead, it is %lu.", bluice_server_record->name, (unsigned long) binary_data_length ); } /* Get the length of the text data. */ message_header[MX_BLUICE_MSGHDR_BINARY] = '\0'; /* Null terminate it. */ text_data_length = atol( message_header ); total_data_length = text_data_length + binary_data_length; #if 0 MX_DEBUG(-2,("%s: text = %lu, binary = %lu, total = %lu", fname, (unsigned long) text_data_length, (unsigned long) binary_data_length, (unsigned long) total_data_length)); #endif if ( data_buffer == NULL ) { data_pointer = bluice_server->receive_buffer; maximum_length = bluice_server->receive_buffer_length; } else { data_pointer = data_buffer; maximum_length = data_buffer_length; } if ( total_data_length > maximum_length ) { mx_warning( "Truncating a %lu byte message body from " "Blu-Ice server '%s' to %lu bytes.", (unsigned long) total_data_length, bluice_server_record->name, (unsigned long) maximum_length ); total_data_length = maximum_length; } /* Now receive the data for the message. */ mx_status = mx_socket_receive( bluice_server_socket, data_pointer, total_data_length, &actual_bytes_received, NULL, 0, 0 ); #if BLUICE_DEBUG_MESSAGE MX_DEBUG(-3,("%s: received '%s' from server '%s'.", fname, data_pointer, bluice_server_record->name)); #endif *actual_data_length = (long) actual_bytes_received; if ( actual_bytes_received < maximum_length ) { data_pointer[actual_bytes_received] = '\0'; } return mx_status; }
int motor_gpib_fn( int argc, char *argv[] ) { static const char cname[] = "gpib"; MX_RECORD *record; int cmd_type, status, address; size_t length; mx_status_type mx_status; static char usage[] = "\n" "Usage: gpib 'record_name' address getline\n" " gpib 'record_name' address putline \"text to send\"\n" " gpib 'record_name' address command \"text to send\"\n" " gpib 'record_name' address cmd \"text to send\"\n\n"; if ( argc <= 4 ) { fputs( usage, output ); return FAILURE; } record = mx_get_record( motor_record_list, argv[2] ); if ( record == NULL ) { fprintf( output, "\n%s: There is no record named '%s'.\n\n", cname, argv[2] ); return FAILURE; } if ( ( record->mx_superclass != MXR_INTERFACE ) || ( record->mx_class != MXI_GPIB ) ) { fprintf( output, "\n%s: Record '%s' is not an GPIB port.\n\n", cname, argv[2] ); return FAILURE; } address = atoi( argv[3] ); length = strlen( argv[4] ); if ( strncmp( "getline", argv[4], max(4,length) ) == 0 ) { cmd_type = GPIB_GETLINE_CMD; } else if ( strncmp( "putline", argv[4], max(1,length) ) == 0 ) { cmd_type = GPIB_PUTLINE_CMD; } else if ( strncmp( "command", argv[4], max(1,length) ) == 0 ) { cmd_type = GPIB_COMMAND_CMD; } else if ( strncmp( "cmd", argv[4], max(1,length) ) == 0 ) { cmd_type = GPIB_COMMAND_CMD; } else { fputs( usage, output ); return FAILURE; } if ( cmd_type == GPIB_GETLINE_CMD ) { if ( argc != 5 ) { fputs( usage, output ); return FAILURE; } } else { if ( argc != 6 ) { fputs( usage, output ); return FAILURE; } } /* Both putline and command send a string here. */ if ( ( cmd_type == GPIB_PUTLINE_CMD ) || ( cmd_type == GPIB_COMMAND_CMD ) ) { mx_status = mx_gpib_putline( record, address, argv[5], NULL, GPIB_DEBUG ); if ( mx_status.code != MXE_SUCCESS ) return FAILURE; } switch( cmd_type ) { case GPIB_PUTLINE_CMD: /* Putline is done at this point. */ return SUCCESS; case GPIB_GETLINE_CMD: status = motor_gpib_readline( record, address ); if ( status == FAILURE ) { fprintf( output, "gpib: No new response is available.\n" ); return FAILURE; } break; case GPIB_COMMAND_CMD: mx_msleep(500); status = motor_gpib_readline( record, address ); if ( status == FAILURE ) { fprintf( output, "gpib: No response is available.\n" ); return FAILURE; } break; default: fprintf( output, "gpib: Unrecognized command line.\n" ); return FAILURE; } return SUCCESS; }
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; }
static mx_status_type child_function( MX_THREAD *thread, void *args ) { mutex_pair_t *mutex_pair; long status, exit_status; int exit_loop; fprintf(stderr, "Child: Child thread starting.\n"); #if 0 mx_show_thread_info( thread, "Child thread:" ); #endif if ( args == NULL ) { fprintf(stderr, "Child: args pointer was NULL. Exiting...\n"); exit(1); } mutex_pair = (mutex_pair_t *) args; /* Lock the child mutex. */ fprintf( stderr, "Child: Locking child mutex.\n" ); status = mx_mutex_lock( mutex_pair->child_mutex ); if ( status != MXE_SUCCESS ) { fprintf( stderr, "Child: Attempt to lock the child mutex failed with MX status code = %ld.\n", status ); exit( status ); } /* Busy wait for the parent mutex. */ fprintf( stderr, "Child: Waiting to lock the parent mutex.\n" ); exit_loop = FALSE; while( exit_loop == FALSE ) { status = mx_mutex_trylock( mutex_pair->parent_mutex ); switch( status ) { case MXE_SUCCESS: exit_loop = TRUE; break; case MXE_NOT_AVAILABLE: fprintf(stderr, "Child: Parent mutex not available.\n"); break; default: fprintf( stderr, "Child: Attempt to lock the parent mutex failed with MX status code = %ld.\n", status ); exit( status ); break; } mx_msleep(500); } /* Once we have acquired the parent mutex, release it. */ fprintf( stderr, "Child: Parent mutex locked. It will now be unlocked.\n"); status = mx_mutex_unlock( mutex_pair->parent_mutex ); if ( status != MXE_SUCCESS ) { fprintf( stderr, "Child: Attempt to unlock the parent mutex failed with MX status code = %ld.\n", status ); exit( status ); } /* Sleep for 5 seconds. */ fprintf( stderr, "Child: Sleeping for 5 seconds.\n" ); mx_msleep(5000); /* Unlock the child mutex. */ fprintf( stderr, "Child: Unlocking the child mutex.\n" ); status = mx_mutex_unlock( mutex_pair->child_mutex ); if ( status != MXE_SUCCESS ) { fprintf( stderr, "Child: Attempt to unlock the child mutex failed with MX status code = %ld.\n", status ); exit( status ); } exit_status = 456; fprintf( stderr, "Child: Child thread will now terminate with exit status = %ld.\n", exit_status ); (void) mx_thread_exit( thread, exit_status ); /* We should never get here. */ 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; }
int motor_home_fn( int argc, char *argv[] ) { static const char cname[] = "home"; MX_RECORD *record; char *endptr; int direction; double position; unsigned long motor_status; mx_bool_type busy, home_search_succeeded, limit_hit; mx_status_type mx_status; static char usage[] = "Usage: home 'motorname' 'direction' - Perform a home search on 'motorname'\n" "\n" " Normally, direction > 0 causes a search in the positive direction,\n" " while direction < 0 causes a search in the negative direction. Some\n" " drivers that can't do a home search will perform some other operation\n" " related to position calibration. You must examine the individual driver\n" " to see exactly what it will do. In all cases, direction == 0 is performs\n" " some driver specific function.\n"; if ( argc != 4 ) { fprintf(output, "%s\n", usage); return FAILURE; } record = mx_get_record( motor_record_list, argv[2] ); if ( record == (MX_RECORD *) NULL ) { fprintf(output,"%s: invalid motor name '%s'\n",cname,argv[2]); return FAILURE; } /* Is this a motor? */ if ( record->mx_class != MXC_MOTOR ) { fprintf(output,"%s: '%s' is not a motor.\n",cname,argv[2]); return FAILURE; } direction = (int) strtol( argv[3], &endptr, 10 ); if ( *endptr != '\0' ) { fprintf(output, "%s: specified direction '%s' is not a number.\n", cname, argv[3] ); return FAILURE; } /* Start the home search. */ fprintf(output,"*** Home search in progress ***\n"); mx_status = mx_motor_home_search( record, direction, MXF_MTR_SHOW_MOVE ); if ( mx_status.code != MXE_SUCCESS ) return FAILURE; /* Wait for the home search to complete. */ for (;;) { mx_status = mx_motor_get_extended_status( record, &position, &motor_status ); if ( mx_status.code != MXE_SUCCESS ) return FAILURE; fprintf(output, " %g\n", position); if ( mx_user_requested_interrupt() ) { fprintf(output, "*** Home search interrupted ***\n"); (void) mx_motor_soft_abort( record ); break; /* Exit the for(;;) loop. */ } busy = (mx_bool_type) (motor_status & MXSF_MTR_IS_BUSY); if ( busy == FALSE ) { /* The motor has stopped, so exit the for(;;) loop. */ break; } mx_msleep(1000); } mx_status = mx_motor_home_search_succeeded( record, &home_search_succeeded ); if ( mx_status.code != MXE_SUCCESS ) return FAILURE; if ( home_search_succeeded ) { fprintf(output, "*** Home search for motor '%s' completed successfully. ***\n", record->name ); return SUCCESS; } else { /* Check to see if the limit switches are tripped. */ (void) mx_motor_positive_limit_hit( record, &limit_hit ); if ( limit_hit ) { fprintf(output, "*** Positive limit hit for motor '%s'. ***\n", record->name); } (void) mx_motor_negative_limit_hit( record, &limit_hit ); if ( limit_hit ) { fprintf(output, "*** Negative limit hit for motor '%s'. ***\n", record->name); } fprintf(output, "\007*** Home search failed. Motor '%s' is not at the home switch. ***\n", record->name ); return FAILURE; } }
MX_EXPORT mx_status_type mxd_u500_set_parameter( MX_MOTOR *motor ) { static const char fname[] = "mxd_u500_set_parameter()"; MX_U500_MOTOR *u500_motor = NULL; MX_U500 *u500 = NULL; int board_number; char axis_name; double double_value; long long_value; char command[200]; AERERR_CODE wapi_status; mx_status_type mx_status; mx_status = mxd_u500_get_pointers( motor, &u500_motor, &u500, fname ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; board_number = u500_motor->board_number; axis_name = u500_motor->axis_name; switch( motor->parameter_type ) { case MXLV_MTR_SPEED: /* Just store the value for later use by the INDEX * and FREERUN commands. */ break; case MXLV_MTR_RAW_ACCELERATION_PARAMETERS: /* The acceleration must be specified in counts/msec**2 */ sprintf( command, "AC %c%ld", u500_motor->axis_name, 1.0e-6 * motor->raw_acceleration_parameters[0] ); mx_status = mxi_u500_command( u500, board_number, command ); break; case MXLV_MTR_AXIS_ENABLE: if ( motor->axis_enable ) { motor->axis_enable = 1; snprintf( command, sizeof(command), "EN %c", u500_motor->axis_name ); } else { snprintf( command, sizeof(command), "DI %c", u500_motor->axis_name ); } mx_status = mxi_u500_command( u500, board_number, command ); break; #if 0 case MXLV_MTR_CLOSED_LOOP: if ( motor->closed_loop ) { } else { } break; #endif case MXLV_MTR_FAULT_RESET: /* First send an abort command. */ mx_status = mxi_u500_command( u500, board_number, "AB" ); /* FIXME: Do we need to insert a delay here for it to * respond to the abort? */ mx_msleep(1000); #if U500_DEBUG MX_DEBUG(-2,("%s: Invoking WAPIAerFaultAck()", fname)); #endif wapi_status = WAPIAerFaultAck(); if ( wapi_status != 0 ) { return mxi_u500_error( wapi_status, fname, "Attempt to acknowledge a fault for motor '%s' failed.", motor->record->name ); } break; case MXLV_MTR_PROPORTIONAL_GAIN: long_value = mx_round( motor->proportional_gain ); sprintf( command, "GA %c KPOS%ld", axis_name, long_value ); mx_status = mxi_u500_command( u500, board_number, command ); break; case MXLV_MTR_INTEGRAL_GAIN: long_value = mx_round( motor->integral_gain ); sprintf( command, "GA %c KI%ld", axis_name, long_value ); mx_status = mxi_u500_command( u500, board_number, command ); break; case MXLV_MTR_DERIVATIVE_GAIN: long_value = mx_round( motor->derivative_gain ); sprintf( command, "GA %c KP%ld", axis_name, long_value ); mx_status = mxi_u500_command( u500, board_number, command ); break; case MXLV_MTR_VELOCITY_FEEDFORWARD_GAIN: long_value = mx_round( motor->velocity_feedforward_gain ); sprintf( command, "GA %c VFF%ld", axis_name, long_value ); mx_status = mxi_u500_command( u500, board_number, command ); break; case MXLV_MTR_ACCELERATION_FEEDFORWARD_GAIN: long_value = mx_round( motor->acceleration_feedforward_gain ); sprintf( command, "GA %c AFF%ld", axis_name, long_value ); mx_status = mxi_u500_command( u500, board_number, command ); break; default: mx_status = mx_motor_default_set_parameter_handler( motor ); break; } return mx_status; }
static mx_status_type mxd_bluice_area_detector_collect_thread( MX_THREAD *thread, void *args ) { static const char fname[] = "mxd_bluice_area_detector_collect_thread()"; MX_AREA_DETECTOR *ad; MX_BLUICE_AREA_DETECTOR *bluice_area_detector; MX_BLUICE_SERVER *bluice_server; MX_BLUICE_FOREIGN_DEVICE *collect_operation; MX_BLUICE_FOREIGN_DEVICE *transfer_operation; MX_BLUICE_FOREIGN_DEVICE *oscillation_ready_operation; int num_items; int current_collect_state, commanded_collect_state; int current_transfer_state, current_oscillation_ready_state; char command[200]; char start_oscillation_format[40]; char prepare_for_oscillation_format[40]; char request_name[40]; char motor_name[MXU_BLUICE_NAME_LENGTH+1]; double oscillation_time, new_motor_position; unsigned long client_number; int32_t operation_counter; mx_status_type mx_status; if ( args == NULL ) { return mx_error( MXE_NULL_ARGUMENT, fname, "The MX_AREA_DETECTOR pointer passed was NULL." ); } ad = (MX_AREA_DETECTOR *) args; mx_status = mxd_bluice_area_detector_get_pointers( ad, &bluice_area_detector, &bluice_server, NULL, fname ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; #if MXD_BLUICE_AREA_DETECTOR_DEBUG MX_DEBUG(-2,("%s invoked for Blu-Ice detector '%s'", fname, ad->record->name )); #endif collect_operation = bluice_area_detector->collect_operation; if ( collect_operation == (MX_BLUICE_FOREIGN_DEVICE *) NULL ) { return mx_error( MXE_INITIALIZATION_ERROR, fname, "No collect operation has been configured for area detector '%s'.", ad->record->name ); } transfer_operation = bluice_area_detector->transfer_operation; if ( transfer_operation == (MX_BLUICE_FOREIGN_DEVICE *) NULL ) { return mx_error( MXE_INITIALIZATION_ERROR, fname, "No transfer operation has been configured for area detector '%s'.", ad->record->name ); } oscillation_ready_operation = bluice_area_detector->oscillation_ready_operation; if ( oscillation_ready_operation == (MX_BLUICE_FOREIGN_DEVICE *) NULL ) { return mx_error( MXE_INITIALIZATION_ERROR, fname, "No oscillation_ready operation has been configured for area detector '%s'.", ad->record->name ); } snprintf( start_oscillation_format, sizeof(start_oscillation_format), "%%%ds %%%ds %%lg", (int) sizeof(request_name)+1, (int) sizeof(motor_name)+1 ); snprintf( prepare_for_oscillation_format, sizeof(prepare_for_oscillation_format), "%%%ds %%lg", (int) sizeof(request_name)+1 ); /*-------------------------------------------*/ /* Send the collect command which was formatted in the main thread * in the function mxd_bluice_area_detector_trigger(). */ commanded_collect_state = MXSF_BLUICE_OPERATION_STARTED; mx_bluice_set_operation_state( collect_operation, commanded_collect_state ); mx_status = mx_bluice_send_message( bluice_server->record, bluice_area_detector->collect_command, NULL, 0); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* The Collect operation may perform multiple exposures, * so we loop over the exposures here. */ while (1) { /*-------------------------------------------*/ /* Wait until the Collect operation changes its state. */ current_collect_state = mx_bluice_get_operation_state( collect_operation ); while ( current_collect_state == commanded_collect_state ) { mx_msleep(1); current_collect_state = mx_bluice_get_operation_state( collect_operation ); } if ( current_collect_state != MXSF_BLUICE_OPERATION_UPDATED ) { return mx_error( MXE_UNKNOWN_ERROR, fname, "Unexpected operation state %d seen for the collect " "operation of Blu-Ice area detector '%s'.", current_collect_state, ad->record->name ); } /*-------------------------------------------*/ /* We should have received a start_oscillation request here. * Try to parse it. */ num_items = sscanf( collect_operation->u.operation.arguments_buffer, start_oscillation_format, request_name, motor_name, &oscillation_time ); if ( num_items != 3 ) { return mx_error( MXE_UNPARSEABLE_STRING, fname, "The operation update string '%s' for operation '%s' " "of area detector '%s' could not be parsed into a " "request name, motor name, and oscillation time.", collect_operation->u.operation.arguments_buffer, collect_operation->name, ad->record->name ); } #if MXD_BLUICE_AREA_DETECTOR_DEBUG MX_DEBUG(-2, ("%s: request_name = '%s', motor_name = '%s', oscillation_time = %f", fname, request_name, motor_name, oscillation_time)); #endif if ( strcmp( request_name, "start_oscillation" ) != 0 ) { return mx_error( MXE_NETWORK_IO_ERROR, fname, "Unexpected '%s' request seen in update '%s' for " "operation '%s' of area detector '%s'. " "We expected to see 'start_oscillation' here.", request_name, collect_operation->u.operation.arguments_buffer, collect_operation->name, ad->record->name ); } /*-------------------------------------------*/ /* Acknowledge the update. */ commanded_collect_state = MXSF_BLUICE_OPERATION_UPDATE_ACKNOWLEDGED; mx_bluice_set_operation_state( collect_operation, commanded_collect_state ); /*-------------------------------------------*/ /* FIXME: Here we either invoke an 'expose' operation or the * 'stoh_start_oscillation' command. */ mx_warning( "FIXME FIXME FIXME!\n" "****** This is where we would do the 'expose' operation. ******\n" "FIXME FIXME FIXME!" ); /* FIXME: Now we claim that the oscillation is over. */ /*-------------------------------------------*/ /* Send 'detector_transfer_image' to the area detector to tell * it to read out the image. */ client_number = mx_bluice_get_client_number( bluice_server ); operation_counter = mx_bluice_update_operation_counter( bluice_server ); snprintf( command, sizeof(command), "stoh_start_operation detector_transfer_image %lu.%lu", client_number, (unsigned long) operation_counter ); mx_bluice_set_operation_state( transfer_operation, MXSF_BLUICE_OPERATION_STARTED ); mx_status = mx_bluice_send_message( bluice_server->record, command, NULL, 0); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /*-------------------------------------------*/ /* Wait until the Transfer operation changes its state. */ current_transfer_state = mx_bluice_get_operation_state( transfer_operation ); while (current_transfer_state == MXSF_BLUICE_OPERATION_STARTED) { mx_msleep(1); current_transfer_state = mx_bluice_get_operation_state( transfer_operation ); } if ( current_transfer_state != MXSF_BLUICE_OPERATION_COMPLETED ) { return mx_error( MXE_UNKNOWN_ERROR, fname, "Unexpected operation state %d seen for the transfer " "operation of Blu-Ice area detector '%s'.", current_transfer_state, ad->record->name ); } /*-------------------------------------------*/ /* Wait until the Command operation changes its state. */ current_collect_state = mx_bluice_get_operation_state( collect_operation ); while ( current_collect_state == commanded_collect_state ) { mx_msleep(1); current_collect_state = mx_bluice_get_operation_state( collect_operation ); } switch( current_collect_state ) { case MXSF_BLUICE_OPERATION_UPDATED: /* We will be acquiring another frame. */ break; case MXSF_BLUICE_OPERATION_COMPLETED: #if MXD_BLUICE_AREA_DETECTOR_DEBUG MX_DEBUG(-2, ("%s: COLLECT HAS SUCCEEDED! for detector '%s'. " "This thread will exit now.", fname, ad->record->name )); #endif /* We have acquired the LAST frame, so the collect * operation is over. We can now exit this thread. */ return MX_SUCCESSFUL_RESULT; break; default: return mx_error( MXE_UNKNOWN_ERROR, fname, "Unexpected operation state %d seen for the collect " "operation of Blu-Ice area detector '%s'.", current_collect_state, ad->record->name ); } /*-------------------------------------------*/ /* We should have received a prepare_for_oscillation request * here. Try to parse it. */ num_items = sscanf( collect_operation->u.operation.arguments_buffer, prepare_for_oscillation_format, request_name, &new_motor_position ); if ( num_items != 2 ) { return mx_error( MXE_UNPARSEABLE_STRING, fname, "The operation update string '%s' for operation '%s' " "of area detector '%s' could not be parsed into a " "request name and a new motor position.", collect_operation->u.operation.arguments_buffer, collect_operation->name, ad->record->name ); } #if MXD_BLUICE_AREA_DETECTOR_DEBUG MX_DEBUG(-2,("%s: request_name = '%s', new_motor_position = %f", fname, request_name, new_motor_position)); #endif if ( strcmp( request_name, "prepare_for_oscillation" ) != 0 ) { return mx_error( MXE_NETWORK_IO_ERROR, fname, "Unexpected '%s' request seen in update '%s' for " "operation '%s' of area detector '%s'. " "We expected to see 'prepare_for_oscillation' here.", request_name, collect_operation->u.operation.arguments_buffer, collect_operation->name, ad->record->name ); } /*-------------------------------------------*/ /* Acknowledge the update. */ commanded_collect_state = MXSF_BLUICE_OPERATION_UPDATE_ACKNOWLEDGED; mx_bluice_set_operation_state( collect_operation, commanded_collect_state ); /*-------------------------------------------*/ /* FIXME: Here we would move the motor to a new position. */ mx_warning( "FIXME FIXME FIXME!\n" "****** This is where we would do the 'move' operation. ******\n" "FIXME FIXME FIXME!" ); /* FIXME: Now we claim that the move is over. */ /*-------------------------------------------*/ /* Send 'detector_oscillation_ready' to the area detector * to tell it that the motor has reached its new position. */ client_number = mx_bluice_get_client_number( bluice_server ); operation_counter = mx_bluice_update_operation_counter( bluice_server ); snprintf( command, sizeof(command), "stoh_start_operation detector_oscillation_ready %lu.%lu", client_number, (unsigned long) operation_counter ); mx_bluice_set_operation_state( oscillation_ready_operation, MXSF_BLUICE_OPERATION_STARTED ); mx_status = mx_bluice_send_message( bluice_server->record, command, NULL, 0); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /*-------------------------------------------*/ /* Wait until the Oscillation_ready operation changes * its state. */ current_oscillation_ready_state = mx_bluice_get_operation_state(oscillation_ready_operation); while ( current_oscillation_ready_state == MXSF_BLUICE_OPERATION_STARTED ) { mx_msleep(1); current_oscillation_ready_state = mx_bluice_get_operation_state( oscillation_ready_operation ); } if ( current_oscillation_ready_state != MXSF_BLUICE_OPERATION_COMPLETED ) { return mx_error( MXE_UNKNOWN_ERROR, fname, "Unexpected operation state %d seen for the " "oscillation_ready operation of Blu-Ice " "area detector '%s'.", current_oscillation_ready_state, ad->record->name ); } /*-------------------------------------------*/ /* Go back to the top of the loop for another pass. */ #if MXD_BLUICE_AREA_DETECTOR_DEBUG MX_DEBUG(-2, ("%s: Going back to the top of the loop for another frame.", fname)); #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; }
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; }
MX_EXPORT mx_status_type mx_bluice_check_for_master( MX_BLUICE_SERVER *bluice_server ) { static const char fname[] = "mx_bluice_check_for_master()"; MX_BLUICE_DCSS_SERVER *bluice_dcss_server; mx_bool_type master_flag; unsigned long i, wait_ms, max_attempts, auto_take_master; mx_status_type mx_status; mx_status = mx_bluice_is_master( bluice_server, &master_flag ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; if ( master_flag ) { return MX_SUCCESSFUL_RESULT; } else { /* We can only get here for DCSS servers. */ bluice_dcss_server = (MX_BLUICE_DCSS_SERVER *) bluice_server->record->record_type_struct; auto_take_master = bluice_dcss_server->bluice_dcss_flags & MXF_BLUICE_DCSS_AUTO_TAKE_MASTER; if ( auto_take_master ) { mx_status = mx_bluice_take_master(bluice_server, TRUE); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* Wait to become master. */ wait_ms = 100; max_attempts = 50; for ( i = 0; i < max_attempts; i++ ) { mx_status = mx_bluice_is_master( bluice_server, &master_flag ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; if ( master_flag ) { return MX_SUCCESSFUL_RESULT; } mx_msleep( wait_ms ); } return mx_error( MXE_TIMED_OUT, fname, "Timed out after waiting %g seconds to become master " "for Blu-Ice server '%s'.", 0.001 * (double)( wait_ms * max_attempts ), bluice_server->record->name ); } else { return mx_error( MXE_NOT_VALID_FOR_CURRENT_STATE, fname, "Your client is not currently master for " "Blu-Ice server '%s'.", bluice_server->record->name ); } } }
int main( int argc, char *argv[] ) { MX_RECORD *record_list; MX_RECORD *energy_motor_record; MX_RECORD *i_zero_record; MX_RECORD *i_trans_record; MX_RECORD *timer_record; double start, step_size, measurement_time, energy; int i, num_steps, error, busy; long i_zero_value, i_trans_value; mx_status_type status; /* Read in the MX database used by this example. */ status = mx_setup_database( &record_list, DATABASE_FILENAME ); if ( status.code != MXE_SUCCESS ) { fprintf( stderr, "Cannot setup the MX database '%s'.\n", DATABASE_FILENAME ); exit(1); } /* Find the devices to be used by the scan. */ energy_motor_record = mx_get_record( record_list, "energy" ); if ( energy_motor_record == (MX_RECORD *) NULL ) { fprintf( stderr, "Cannot find the motor 'energy'.\n" ); exit(1); } i_zero_record = mx_get_record( record_list, "Io" ); if ( i_zero_record == (MX_RECORD *) NULL ) { fprintf( stderr, "Cannot find the scaler 'Io'.\n" ); exit(1); } i_trans_record = mx_get_record( record_list, "It" ); if ( i_trans_record == (MX_RECORD *) NULL ) { fprintf( stderr, "Cannot find the scaler 'It'.\n" ); exit(1); } timer_record = mx_get_record( record_list, "timer1" ); if ( timer_record == (MX_RECORD *) NULL ) { fprintf( stderr, "Cannot find the timer 'timer1'.\n" ); exit(1); } /* Setup the scan parameters for a copper K edge scan. */ start = 8950; /* in eV */ step_size = 1.0; /* in eV */ num_steps = 101; measurement_time = 1.0; /* in seconds */ /* Perform the scan. */ error = FALSE; printf( "Moving to start position.\n" ); for ( i = 0; i < num_steps; i++ ) { /* Clear the scalers. */ status = mx_scaler_clear( i_zero_record ); if ( status.code != MXE_SUCCESS ) { error = TRUE; break; } status = mx_scaler_clear( i_trans_record ); if ( status.code != MXE_SUCCESS ) { error = TRUE; break; } /* Compute the energy for the next step. */ energy = start + step_size * (double) i; /* Move to the new energy. */ status = mx_motor_move_absolute( energy_motor_record, energy, 0 ); if ( status.code != MXE_SUCCESS ) { error = TRUE; break; } /* Wait for the motor to stop moving. */ busy = TRUE; while ( busy ) { mx_msleep(10); /* Wait for 10 milliseconds */ status = mx_motor_is_busy( energy_motor_record, &busy ); if ( status.code != MXE_SUCCESS ) { error = TRUE; break; } } /* Start the measurement timer. */ status = mx_timer_start( timer_record, measurement_time ); if ( status.code != MXE_SUCCESS ) { error = TRUE; break; } /* Wait until the timer stops counting. */ busy = TRUE; while ( busy ) { mx_msleep(10); /* Wait for 10 milliseconds */ status = mx_timer_is_busy( timer_record, &busy ); if ( status.code != MXE_SUCCESS ) { error = TRUE; break; } } /* Read out the scalers. */ status = mx_scaler_read( i_zero_record, &i_zero_value ); if ( status.code != MXE_SUCCESS ) { error = TRUE; break; } status = mx_scaler_read( i_trans_record, &i_trans_value ); if ( status.code != MXE_SUCCESS ) { error = TRUE; break; } /* Print out the values. */ printf( "%10.3f %10lu %10lu\n", energy, i_zero_value, i_trans_value ); } if ( error ) { fprintf(stderr, "The scan aborted abnormally.\n" ); exit(1); } exit(0); }
static mx_status_type mxp_wedge_scan_take_frame( MX_SCAN *scan, MX_AREA_DETECTOR_SCAN *ad_scan, MX_WEDGE_SCAN *wedge_scan ) { #if MXS_WEDGE_SCAN_DEBUG static const char fname[] = "mxp_wedge_scan_take_frame()"; #endif MX_RECORD *ad_record; MX_AREA_DETECTOR *ad; MX_RECORD *motor_record; MX_MOTOR *motor; MX_RECORD *shutter_record; double delta, oscillation_time; unsigned long ad_status; mx_status_type mx_status; #if MXS_WEDGE_SCAN_DEBUG MX_DEBUG(-2,("%s invoked for scan '%s'", fname, scan->record->name)); #endif ad_record = scan->input_device_array[0]; ad = ad_record->record_class_struct; MXW_UNUSED( ad ); shutter_record = scan->input_device_array[1]; delta = ad_scan->step_size[0]; mx_status = mx_get_last_measurement_time( &(scan->measurement), &oscillation_time ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; motor_record = scan->motor_record_array[0]; motor = motor_record->record_class_struct; MXW_UNUSED( motor ); #if MXS_WEDGE_SCAN_DEBUG MX_DEBUG(-2,("%s: Starting oscillation of '%s' for %f seconds " "using shutter '%s' with an oscillation distance of '%s' for %f %s", fname, ad_record->name, exposure_time, shutter_record->name, motor_record->name, delta, motor->units )); #endif /* FIXME - Move this call to mx_area_detector_setup_oscillation() * to somewhere else, so that we are not doing it for each frame. */ mx_status = mx_area_detector_setup_oscillation( ad_record, motor_record, shutter_record, NULL, delta, oscillation_time ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* Trigger the oscillation. */ mx_status = mx_area_detector_trigger_oscillation( ad_record ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* Wait for the oscillation to finish. */ while(1) { mx_status = mx_area_detector_get_status( ad_record, &ad_status ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; if ( ( ad_status & MXSF_AD_IS_BUSY ) == 0 ) { break; /* Exit the for() loop. */ } mx_msleep(1); } mx_status = mx_add_measurement_to_datafile( &(scan->datafile) ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; #if MXS_WEDGE_SCAN_DEBUG MX_DEBUG(-2,("%s: frame complete.", fname)); #endif 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_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; }
int main( int argc, char *argv[] ) { mutex_pair_t mutex_pair; MX_THREAD *parent_thread, *child_thread; long status, thread_exit_status; int exit_loop; mx_status_type mx_status; mx_set_debug_level(0); fprintf(stderr, "Parent: child_function = %p\n", child_function); mx_status = mx_get_current_thread( &parent_thread ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); #if 0 mx_show_thread_info( parent_thread, "Parent thread:" ); #endif fprintf(stderr, "Parent: Creating parent mutex.\n"); mx_status = mx_mutex_create( &(mutex_pair.parent_mutex) ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); fprintf(stderr, "Parent: Creating child mutex.\n"); mx_status = mx_mutex_create( &(mutex_pair.child_mutex) ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); fprintf(stderr, "Parent: Locking parent mutex.\n"); status = mx_mutex_lock( mutex_pair.parent_mutex ); if ( status != MXE_SUCCESS ) { fprintf(stderr, "Parent: Attempt to lock the parent mutex failed with MX status code = %ld.\n", status ); exit( status ); } fprintf(stderr, "Parent: Creating child thread.\n" ); mx_status = mx_thread_create( &child_thread, child_function, &mutex_pair ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); /* Give the child long enough to lock the child mutex. */ fprintf(stderr, "Parent: Sleeping for 5 seconds.\n"); mx_msleep(5000); /* Unlock the parent mutex so that the child can proceed. */ fprintf(stderr, "Parent: Unlocking parent mutex.\n"); status = mx_mutex_unlock( mutex_pair.parent_mutex ); if ( status != MXE_SUCCESS ) { fprintf( stderr, "Parent: Attempt to unlock the parent mutex failed " "with MX status code = %ld.\n", status ); exit( status ); } /* Wait for the child to unlock its mutex. */ fprintf(stderr, "Parent: Waiting to lock the child mutex.\n"); exit_loop = FALSE; while( exit_loop == FALSE ) { status = mx_mutex_trylock( mutex_pair.child_mutex ); switch( status ) { case MXE_SUCCESS: exit_loop = TRUE; break; case MXE_NOT_AVAILABLE: fprintf(stderr, "Parent: Child mutex not available.\n"); break; default: fprintf( stderr, "Parent: Attempt to lock the child mutex failed with MX status code = %ld.\n", status ); exit( status ); break; } mx_msleep(500); } fprintf(stderr, "Parent: Child mutex locked. It will now be unlocked.\n" ); status = mx_mutex_unlock( mutex_pair.child_mutex ); if ( status != MXE_SUCCESS ) { fprintf( stderr, "Parent: Attempt to unlock the child mutex failed with MX status code = %ld.\n", status ); exit( status ); } /* Wait for the child to finish executing. */ fprintf(stderr, "Parent: Waiting for the child to exit.\n" ); mx_status = mx_thread_wait( child_thread, &thread_exit_status, MX_THREAD_INFINITE_WAIT ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); fprintf(stderr, "Parent: Child thread exit status = %ld.\n", thread_exit_status ); /* Free the data structures used by the child thread. */ fprintf( stderr, "Parent: Freeing child data structures.\n" ); mx_status = mx_thread_free_data_structures( child_thread ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); /* Destroy the parent and child mutexes. */ fprintf( stderr, "Parent: Destroying parent mutex.\n" ); mx_status = mx_mutex_destroy( mutex_pair.parent_mutex ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); fprintf( stderr, "Parent: Destroying child mutex.\n" ); mx_status = mx_mutex_destroy( mutex_pair.child_mutex ); if ( mx_status.code != MXE_SUCCESS ) exit( mx_status.code ); /* Announce to the user that the test is over. */ fprintf(stderr, "Parent: Mutex test completed successfully.\n"); exit(0); }
static mx_status_type mxd_am9513_motor_move_single_step( MX_AM9513_MOTOR *am9513_motor, MX_AM9513 *low_am9513, int m ) { uint16_t saved_counter_mode_register, saved_load_register; mx_status_type mx_status; saved_counter_mode_register = low_am9513->counter_mode_register[m]; saved_load_register = low_am9513->load_register[m]; /* Turn off gating and the count repetitively settings. */ low_am9513->counter_mode_register[m] = saved_counter_mode_register & 0x1fcf; mx_status = mxi_am9513_set_counter_mode_register( low_am9513, m ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* Load a 4 into the counter. A 0 here will not put out any * steps at all. A 1 or 2 results in an anomalously long step * pulse (not known why!) and 3 or more gives the desired short * step pulse. (CUS 050615) */ low_am9513->load_register[m] = 4; mx_status = mxi_am9513_load_counter( low_am9513, m ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* Arm the counter. This should cause the step to occur. */ mx_status = mxi_am9513_arm_counter( low_am9513, m ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* Wait for the step pulse to complete. Unless the delay is * present, a fast computer could reset the Load and Command * registers before the step pulse is complete, resulting in * flaky behavior. It is not clear that the 10ms delay is * optimal but it works and is not too long ;). (CUS 050615) */ mx_msleep( 10 ); /* Now restore the counter parameters. */ low_am9513->counter_mode_register[m] = saved_counter_mode_register; mx_status = mxi_am9513_set_counter_mode_register( low_am9513, m ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; low_am9513->load_register[m] = saved_load_register; mx_status = mxi_am9513_load_counter( low_am9513, m ); if ( mx_status.code != MXE_SUCCESS ) return mx_status; /* Modify the recorded position of the motor. */ if ( am9513_motor->last_direction < 0 ) { am9513_motor->last_destination--; } else { am9513_motor->last_destination++; } return MX_SUCCESSFUL_RESULT; }
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; }
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; }