CWRU High-Speed Flexible Parts Feeder. Software Source Code

Similar documents
Assignment description: This is a C++ project. The comms class containing the

Winsock Server adding Multiple clients support C++

Simple network applications using sockets (BSD and WinSock) Revision 1 Copyright Clifford Slocombe

A. Basic Function Calls for Network Communications

Project 3. Reliable Data Transfer over UDP. NTU CSIE Computer Networks 2011 Spring

Homework # 7 Distributed Computing due Saturday, December 13th, 2:00 PM

CSCE 463/612 Networks and Distributed Processing Spring 2017

CSCE : Computer Systems Homework #1 Part 1 (25 pts) Due date: 1/24/19

CMSC421: Principles of Operating Systems

CMSC 330: Organization of Programming Languages

Assignment 2 Group 5 Simon Gerber Systems Group Dept. Computer Science ETH Zurich - Switzerland

Midterm Exam Amy Murphy 19 March 2003

Εργαστήριο 9 I/O Multiplexing

CSE332: Data Abstractions Lecture 22: Shared-Memory Concurrency and Mutual Exclusion. Tyler Robison Summer 2010

2007 Microsoft Corporation. All rights reserved.

CPS 310 midterm exam #1, 2/19/2016

CS 431 Introduction to Computer Systems Solutions Mid semester exam 2005

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

CSC209H Lecture 9. Dan Zingaro. March 11, 2015

Lecture 9: Multiprocessor OSs & Synchronization. CSC 469H1F Fall 2006 Angela Demke Brown

First Midterm Exam September 28, 2017 CS162 Operating Systems

MySQL for Windows. Tak Auyeung. September 7, 2003

GDB Tutorial. A Walkthrough with Examples. CMSC Spring Last modified March 22, GDB Tutorial

Learning from Bad Examples. CSCI 5828: Foundations of Software Engineering Lecture 25 11/18/2014

CSE 332: Data Structures & Parallelism Lecture 17: Shared-Memory Concurrency & Mutual Exclusion. Ruth Anderson Winter 2019

Synchronization. CS61, Lecture 18. Prof. Stephen Chong November 3, 2011

Threads Tuesday, September 28, :37 AM

There are, of course, many other possible solutions and, if done correctly, those received full credit.

CS 251 Intermediate Programming Methods and Classes

CS 251 Intermediate Programming Methods and More

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

Motivation was to facilitate development of systems software, especially OS development.

A Sophomoric Introduction to Shared-Memory Parallelism and Concurrency Lecture 4 Shared-Memory Concurrency & Mutual Exclusion

CSE 333 Final Exam June 8, 2016 Sample Solution

CPSC/ECE 3220 Fall 2017 Exam Give the definition (note: not the roles) for an operating system as stated in the textbook. (2 pts.

Project Report Number Plate Recognition

Tasks. Task Implementation and management

Distributed Programming

Overview. CMSC 330: Organization of Programming Languages. Concurrency. Multiprocessors. Processes vs. Threads. Computation Abstractions

THREADS AND CONCURRENCY

CS-537: Midterm Exam (Spring 2001)

Thread. Disclaimer: some slides are adopted from the book authors slides with permission 1

CSE 451 Midterm 1. Name:

Lecture 12 CSE July Today we ll cover the things that you still don t know that you need to know in order to do the assignment.

Memory Consistency Models

CS 111. Operating Systems Peter Reiher

#include <tobii/tobii.h> char const* tobii_error_message( tobii_error_t error );

JAVA CONCURRENCY FRAMEWORK. Kaushik Kanetkar

Today: Synchronization. Recap: Synchronization

ECE 435 Network Engineering Lecture 2

What are the most likely declarations of "month" in the old and new versions of the program?

Introduction to OS Synchronization MOS 2.3

CS 167 Final Exam Solutions

Introduction to Computer Networks

Programmazione di sistemi multicore

Background. Old Producer Process Code. Improving the Bounded Buffer. Old Consumer Process Code

What s An OS? Cyclic Executive. Interrupts. Advantages Simple implementation Low overhead Very predictable

Lab 0. Yvan Petillot. Networks - Lab 0 1

CS 333 Introduction to Operating Systems Class 4 Concurrent Programming and Synchronization Primitives

CSE 451: Operating Systems Winter Lecture 7 Synchronization. Steve Gribble. Synchronization. Threads cooperate in multithreaded programs

Concurrent Server Design Multiple- vs. Single-Thread

Lecture 8: September 30

Motivation was to facilitate development of systems software, especially OS development.

Need for synchronization: If threads comprise parts of our software systems, then they must communicate.

CSE 43: Computer Networks Structure, Threading, and Blocking. Kevin Webb Swarthmore College September 14, 2017

NETWORK PROGRAMMING. Instructor: Junaid Tariq, Lecturer, Department of Computer Science

Threads and Parallelism in Java

ECE454 Tutorial. June 16, (Material prepared by Evan Jones)

Operating Systems. Synchronization

Operating Systems, Assignment 2 Threads and Synchronization

CSL373/CSL633 Major Exam Solutions Operating Systems Sem II, May 6, 2013 Answer all 8 questions Max. Marks: 56

CS193k, Stanford Handout #10. HW2b ThreadBank

Computation Abstractions. Processes vs. Threads. So, What Is a Thread? CMSC 433 Programming Language Technologies and Paradigms Spring 2007

Concurrency Control. Synchronization. Brief Preview of Scheduling. Motivating Example. Motivating Example (Cont d) Interleaved Schedules

Project 4: Synchronization

Java Programming Lecture 23

CS193k, Stanford Handout #8. Threads 3

QUIZ on Ch.5. Why is it sometimes not a good idea to place the private part of the interface in a header file?

CS 31: Introduction to Computer Systems : Threads & Synchronization April 16-18, 2019

CS 160: Interactive Programming

Quiz II Solutions MASSACHUSETTS INSTITUTE OF TECHNOLOGY Fall Department of Electrical Engineering and Computer Science

minit Felix von Leitner September 2004 minit

Asynchronous Events on Linux

OS Structure, Processes & Process Management. Don Porter Portions courtesy Emmett Witchel

Windows Sockets: A Quick And Dirty Primer

Exceptions and Design

THREADS & CONCURRENCY

Pebbles Kernel Specification September 26, 2004

SpiNNaker Application Programming Interface (API)

CROWDMARK. Examination Midterm. Spring 2017 CS 350. Closed Book. Page 1 of 30. University of Waterloo CS350 Midterm Examination.

Final Exam Solutions May 11, 2012 CS162 Operating Systems

CS5460: Operating Systems

Background. The Critical-Section Problem Synchronisation Hardware Inefficient Spinning Semaphores Semaphore Examples Scheduling.

Security impact of noexcept

COMP 3430 Robert Guderian

PROCESSES AND THREADS THREADING MODELS. CS124 Operating Systems Winter , Lecture 8

CS113: Lecture 4. Topics: Functions. Function Activation Records

Concurrency & Parallelism. Threads, Concurrency, and Parallelism. Multicore Processors 11/7/17

Operating Systems (234123) Spring (Homework 3 Wet) Homework 3 Wet

CS61C Machine Structures. Lecture 4 C Pointers and Arrays. 1/25/2006 John Wawrzynek. www-inst.eecs.berkeley.edu/~cs61c/

Transcription:

CWRU High-Speed Flexible Parts Feeder Software Source Code

Source File List Overall Control master_control_loop.h master_control_loop.cpp main_control.h main_control.cpp main_control_sub_systems.cpp main_control_update_users.cpp remote_user.h remote_user.cpp remote_user_handle_updates.cpp remote_user_service_request.cpp Servers Robot Motion RobotMotionServer.h robotmotionserver.cpp robot_server_utility_commands.cpp robot_server_move.cpp report_parameters.cpp set_parameters.cpp other_functions.cpp Robot Position position_server.h position_server.cpp position_server_utility_commands.cpp get_current_position.cpp Vision System CVisionSystem.h CVisionSystem.cpp blob.h blob.cpp Conveyor Motion conveyor_server.h conveyor_server.cpp conv_move_cmds.cpp conv_report.cpp conv_set.cpp conv_server_utilities.cpp I/O Server io.h io.cpp io_server_utility_commands.cpp set_get.cpp io_interest.h io_interest.cpp Utilities structs_and_consts.h Adept_conveyor_encoder.h Adept_conveyor_encoder.cpp semaphore.h semaphore.cpp semaphore_open.h semaphore_open.cpp monitor.h monitor.cpp condition.h condition.cpp CPart.h CPart.cpp queue.h queue.cpp parts_queue.h parts_queue.cpp Message.h Message.cpp m_queue.h m_queue.cpp message_queue.h message_queue.cpp double_check_guard.h double_check_guard.cpp dup_part.h dup_part.cpp timer.h timer.cpp Part Specific Objects Abstract Base Class part_specific_info.h part_factory.h auto_adjuster.h locator.h positioner.h retriever.h retriever.cpp Lenses (2 dia disks) lens_factory.h lens_factory.cpp lens_auto_adjuster.h lens_auto_adjuster.cpp lens_locator.h lens_locator.cpp lens_positioner.h lens_positioner.cpp lens_retriever.h lens_retriever.cpp Squares (2 squares, corner removed) square_factory.h square_factory.cpp square_auto_adjuster.h square_auto_adjuster.cpp square_locator.h square_locator.cpp square_positioner.h square_positioner.cpp square_retriever.h square_retriever.cpp Lenses and Squares Combined l_s_factory.h l_s_factory.cpp l_s_auto_adjuster.h l_s_auto_adjuster.cpp l_s_locator.h l_s_locator.cpp l_s_positioner.h l_s_positioner.cpp l_s_retriever.h l_s_retriever.cpp

Test Stubs conveyor_test_prog.cpp encoder_test.cpp io_test_prog.cpp queue_test_prog.cpp position_test_prog.cpp robot_test_prog.cpp Vision_tester.cpp User Interface GUI Feeder_GUI_panel.java ComboBoxRenderer.java fc.java feederexception.java FormattedDocument.java format_seconds.java JButtonAdapter.java JComboBoxAdapter.java JDecimalField.java JMenuItemAdapter.java JSliderAdapter.java Message_window.java part.java pop_up.java remote_feeder.java space_label.java string_to_num.java time_format.java V+ Code robot_pos_io_server.pg Calibration calibrate.cpp

master_control_loop.h 1/2 master_control_loop.h 2/2 /*! \file master_control_loop.h \author Greg Causey \date 2/15/01 \par Revision History The following revisions have been made to the program. \par Description: This is the main function which starts off the whole feeder system. It creates the singleton server in an orderly manor, creates a socket, then listens for remote user logins. It creates remote_user objects to handle each user. When exiting, it shuts down the singleton servers in an orderly manor. \brief The main function that starts off the whole system. /*! \fn int main(void) \brief The \em main function in the system. Everything starts from here. /*! \fn int user_thread(remote_user *user) \brief The function that runs to handle each user. \brief The port on which the server listens for user login requests. #include <winsock2.h> #include "RobotMotionServer.h" #include "position_server.h" #include "io.h" #include "conveyor_server.h" #include "parts_queue.h" #include "CVisionSystem.h" #include "Adept_conveyor_encoder.h" #include "remote_user.h" #include <stdio.h> #include <conio.h> // ##### #DEFINES ##### // Socket stuff #define BUF_SIZE 256 #define SERVER_PORT 23 //4993 // ##### FUNCTION PROTOTYPES ##### int main(void); int user_thread(remote_user *user); bool create_singleton_servers(); void delete_singleton_servers(); This function is spun off as a thread for each user that logs in. It servers that particular user only. When the user logs out, the thread is terminated. \param *user A pointer to the remote_user object which has been created to service the user which just logged in. /*! \fn bool create_singleton_servers() \brief Create the singleton server in the system. This function creates the singleton servers in the system. They are create in the proper order such that any failures in create can be attributed to the proper server. Order is important because inter relationships have the potential to cause failures at unexpected points in the creation process. E.g. if server1 uses server2, then server1 calls server2::instance() in its constructor. If server2 fails, then the error shows a failure in server1, which is incorrect. Order should be (as of 10/26/01) # conveyor server # vision system # parts %queue # position server # robot motion server # Adept conveyor encoder # I/O server # main control /*! \fn void delete_singleton_servers() \brief Function to destroy the singleton server in the order opposite creation. /*! \def BUF_SIZE \brief The size of the buffer which holds incoming requests from the socket. /*! \def SERVER_PORT

master_control_loop.cpp 1/5 master_control_loop.cpp 2/5 #include "master_control_loop.h" int main(void) { // socket stuff SOCKET soc_des, soc_temp; struct sockaddr_in server; WORD wversionrequested; WSADATA wsadata; fd_set incoming; struct timeval tv; int select_ret; remote_user *temp_user; HANDLE user_thread_handle; DWORD user_thread_id; char input; bool shutdown_the_feeder = false; // ################################################### // Initialize all the servers // ################################################### // Instantiate all the "singleton" servers in the system. Define a // "singleton" server as one in which the singleton design pattern // is used to ensure only a single copy of the server exists in the // system. Singleton servers are usually those that interface with // external harware (although not always). These servers are the // most likely to fail during system startup, since they assume that // the hardware which they are controlling is in some preset state // (e.g. Adept controller ready to accept socket connections). While // this "preset" state should happen automatically, if it doesn t, // this will prevent the program from continuing. While this // initial startup is not totally necessary, this will allow us to // make sure the servers have been created successfully. If any of // the servers fail to instanciate, then we can print a message and // exit cleanly here rather than have the whole thing blowup in the // users face later. if(! create_singleton_servers()) { printf("a server failed to be created. Exiting now!!!!\n\n"); delete_singleton_servers(); Sleep(10000); exit( 1); // ################################################### // Initialize the front end TCP socket // ################################################### // open a TCP socket for front end interaction // windows Gibberish wversionrequested = MAKEWORD(2,2); if((wsastartup(wversionrequested, &wsadata)) == SOCKET_ERROR) WSACleanup(); if(lobyte(wsadata.wversion)!= 2 HIBYTE(wsadata.wVersion)!= 2) WSACleanup(); // create socket if( (soc_des = socket(af_inet,sock_stream,0)) == INVALID_SOCKET) WSACleanup(); memset(&server,0,sizeof(server)); server.sin_addr.s_addr = htonl(inaddr_any); server.sin_family = AF_INET; server.sin_port = htons(server_port); // bind the socket if(bind(soc_des, (struct sockaddr *) &server, sizeof(server)) == SOCKET_ERROR) { perror("socket bind failed"); WSACleanup(); exit( 1); // listen on the socket if(listen(soc_des,1) == SOCKET_ERROR) { perror("socket listen failed"); WSACleanup(); exit( 1); // setup the data structures for the select system call. We need to // use the select call so that we come up for air ever now and then // and see if we should shutdown the system. The user may press a // "q" or "Q" to from the console to indicate that we should // shutdown. We need a readfds structure which contains the socket // and a timeval structure which contains the amount of time to wait // for a connection before returning (from the select call) anyway. FD_ZERO(&incoming); FD_SET(soc_des, &incoming); tv.tv_sec = 1; tv.tv_usec = 0; // now enter a loop waiting for a connection. When we get a // connection, creae a new user object and spin off a thread to // handle it. printf("========================================================\n"); printf("cwru HIGH SPEED FLEXIBLE PARTS FEEDING SYSTEM\n\n"); printf("system now running and accepting connections...\n\n"); printf("press \"q\" to shutdown\n\n"); printf("========================================================\n\n"); while(! shutdown_the_feeder) { select_ret = select(0, &incoming, NULL, NULL, &tv); if(select_ret == 1) { soc_temp = accept(soc_des, NULL, NULL); if(soc_temp == INVALID_SOCKET) { // something is very wrong, exit here WSACleanup(); else { // we have a user request, create a new user object and spin off // a thread to handle them temp_user = new remote_user(soc_temp); if((user_thread_handle = (HANDLE)_beginthreadex(NULL, 0, (unsigned int ( stdcall *)(void *))user_thread, temp_user, 0, (unsigned int *)&user_thread_id)) == 0) { // thread creation failed printf("couldn t create a user thread\n"); else if(select_ret == 0) { // no one is requesting a connection, see if we should shutdown. // NOTE: Be aware that this simple shuts everything down without // regard to the current status of the feeder or of the users // who might be logged in. This shoulw only be called when the // feeder is stopped and when no users are logged in. if(_kbhit() ) { input = _getch(); if(input == q input == Q ) { shutdown_the_feeder = true; else { printf("press q to shutdown the feeder\n");

master_control_loop.cpp 3/5 master_control_loop.cpp 4/5 else if(select_ret == SOCKET_ERROR) { printf("got an error from the select() call: %d\n", WSAGetLastError()); Sleep(1000); //reset the timeval structure. Not necessary under windows, but it //is under other OS s (eg. Linux) tv.tv_sec = 1; tv.tv_usec = 0; // reset the FD_SET structure if(fd_isset(soc_des, &incoming) == 0) FD_SET(soc_des, &incoming); printf("\n========================================================\n"); printf("cwru HIGH SPEED FLEXIBLE PARTS FEEDING SYSTEM\n\n"); printf("system shutdown request received. System shutting down...\n\n"); printf("========================================================\n\n"); // totally done, close the socket closesocket(soc_des); // turn off the return conveyor and light. This should have already // happened, unless the system crashed. io* iosrv = io::instance(); iosrv >set_io( RETURN_CONVEYOR); iosrv >set_io( BACKLIGHT); // ################################################### // Delete the singleton servers // ################################################### delete_singleton_servers(); // ################################################### // All done, exit // ################################################### return(0); int user_thread(remote_user *user) { // someone is trying to login. Make sure they are validated. if(user >login()) { // this is a valid user // enter the processing loop. Wait for the user object to report // that a request has arrived. while(! user >finished) { user >get_request(); user >service_request(); // user is finished, delete the user and exit delete user; _endthreadex(0); return(0); bool create_singleton_servers() { // order is important because inter relationships have the potential // to cause failures at unexpected points in the creation // process. E.g. if server1 uses server2, then server1 calles // server2::instance() in its constructor. If server2 fails, then // the error shows a failure in server1, which is incorrect. // order should be: // 1) conveyor server // 2) vision system // 3) parts queue // 4) position server // 5) robot motion server // 6) Adept conveyor encoder // 7) I/O server // 8) main control // make sure we ckean up after ourselves when a server fails and we // have to exit. Only delete what has already been created. if(conv_server::instance() == NULL) { printf("conveyor Motion Server construction failed\n"); printf("if the PC was just rebooted, you need to log in as\n"); printf("root and open a terminal window to the motion server.\n"); printf("this will re initialize the communications between\n"); printf("the motion control card and the PC. After this, the\n"); printf("constructor should return successfully.\n\n"); return false; if(cvisionsystem::instance() == NULL) { printf("matrox Vision System construction failed\n"); delete conv_server::instance(); return false; if(parts_queue::instance() == NULL) { printf("parts Queue construction failed\n"); delete CVisionSystem::instance(); delete conv_server::instance(); return false; if(position_server::instance() == NULL) { printf("robot Position Server construction failed\n"); delete parts_queue::instance(); delete CVisionSystem::instance(); delete conv_server::instance(); return false; if(robot_motion_server::instance() == NULL) { printf("robot Motion Server creation failed\n"); delete position_server::instance(); delete parts_queue::instance(); delete CVisionSystem::instance(); delete conv_server::instance(); return false; if(adept_conveyor_encoder::instance() == NULL) { printf("adept Conveyor Encoder construction failed\n"); delete robot_motion_server::instance(); delete position_server::instance(); delete parts_queue::instance(); delete CVisionSystem::instance(); delete conv_server::instance(); return false; if(io::instance() == NULL) { printf("io Server creation failed\n"); delete adept_conveyor_encoder::instance(); delete robot_motion_server::instance(); delete position_server::instance(); delete parts_queue::instance(); delete CVisionSystem::instance();

master_control_loop.cpp 5/5 delete conv_server::instance(); return false; if(main_control::instance() == NULL) { printf("main Control Object construction failed\n"); delete io::instance(); delete adept_conveyor_encoder::instance(); delete robot_motion_server::instance(); delete position_server::instance(); delete parts_queue::instance(); delete CVisionSystem::instance(); delete conv_server::instance(); return false; return true; void delete_singleton_servers() { // servers should be deleted in the opposite order of creation. See // create_singleton_server() for creation order. delete main_control::instance(); delete io::instance(); delete adept_conveyor_encoder::instance(); delete robot_motion_server::instance(); delete position_server::instance(); delete parts_queue::instance(); delete CVisionSystem::instance(); delete conv_server::instance();

main_control.h 1/19 main_control.h 2/19 /*! \class main_control \brief The main control loop that oversees the operation of the flexible parts feeder. \author Greg Causey \date 1/28/01 \par Revision History The following revisions have been made to the class. \par Description: This is the main control loop that oversees the operation of the system. This object is responsible for starting, stopping, and pausing the threads which control the robot, the vision system, the conveyors, and the auto adjuster. It is also responsible for creating part specific factories that the threads use to feed parts. It must also destroy those factories and create new ones when a %user wishes to feed a different part. Finally, it is responsible for maintaining the list of users which have logged in and which %user (if any) currently has \em control. Control is defined as having the ability to change the system state (start it, stop it, change speeds, etc...). Only one %user may have control at any given time, all other users can only observe the system. \par This object creates an extra thread to handle the updates to the remote users. This is done so that system performance is not hindered by the number of remote users. (e.g., we don t want the robot waiting for all remote users to be updated before retrieving the next part.) The thread runs the static method update_thread(main_control *mc) and is signaled using a message %queue. server object failed. If the call to the conveyor server was successfully, the method signals the update thread to send an update to all registered users before returning. \param thread_id Identifier of the thread that is making the horizontal speed request. \param speed The new speed of the horizontal conveyor. \return 0 on success. ERROR_NO_CONTROL if the thread which made the request didn t have control. ERROR_SYSTEM_CALL_FAILED if the operation failed. /*! \fn int main_control::set_inc_percentage(dword thread_id, int percent) \brief Set the speed of the inclined conveyor as a percentage of the speed of the horizontal conveyor. This method is used to change the speed of the inclined conveyor. The speed of the inclined conveyor is specified as a percentage of the speed of the horizontal conveyor and this method alters that percentage. The %user must have control for this method to perform the requested action. The method returns a 0 on success, ERROR_NO_CONTROL is the %user didn t have control, and ERROR_SYSTEM_CALL_FAILED if the call to the conveyor server object failed. If the call to the conveyor server was successfully, the method signals the update thread to send an update to all registered users before returning. \param thread_id Identifier of the thread that is making the inclined speed request. /*! \fn main_control::main_control() \param percentage The new speed of the inclined conveyor, given as a percentage of the current speed of the horizontal conveyor. \brief Constructor for the class. Use initialize() to get a pointer to the class due to the singleton construct. The constructor must initialize the system state variables to align with the current feeder settings. The state of the system is held in a system state object. It must also initialize the data structure which holds the current logged in users. Currently logged in users are held in a link list of nodes. Each %user is identified by the thread ID of the thread which is servicing remote requests. The %user thread uses its thread ID when making requests to the main control for validation. This method is never actually called due to the singleton construct. Use the initialize method define below to get a handle to this object. The constructor is declared private to prevent its direct access. \return None. /*! \fn main_control::~main_control() \brief Destructor. Use with caution due to the singleton construct. The destructor clears out the list of logged in users (it should really be empty if this is getting called) and deletes the state object before exiting. \return 0 on success. ERROR_NO_CONTROL if the thread which made the request didn t have control. ERROR_SYSTEM_CALL_FAILED if the operation failed. /*! \fn int main_control::set_robot_speed(dword thread_id, int speed) \brief Set the speed of the robot on the Adept controller. This method is used to change the speed of the robot. The speed of the robot is specified as a percentage of the maximum speed (on a scale of 0% 200%). The actual speed of the robot is a combination of this speed and the monitor speed. The monitor speed can only be set from the adept console. The %user must have control for this method to perform the requested action. The method returns a 0 on success, ERROR_NO_CONTROL is the %user didn t have control, and ERROR_SYSTEM_CALL_FAILED if the call to the conveyor server object failed. If the call to the robot server was successfully, the method signals the update thread to send an update to all registered users before returning. \param thread_id Identifier of the thread that is making the robot speed request. \param speed The new speed of the robot on the Adept controller. \return None. /*! \fn int main_control::set_hor_speed(dword thread_id, double speed) \brief Set the horizontal speed of the conveyor. \return 0 on success. ERROR_NO_CONTROL if the thread which made the request didn t have control. ERROR_SYSTEM_CALL_FAILED if the operation failed. /*! \fn int main_control::change_system_operation(dword thread_id, int new_state) This method is used to set a new speed for the horizontal conveyor. The %user must have control for this to happen. The method returns a 0 on success, ERROR_NO_CONTROL is the %user didn t have control, and ERROR_SYSTEM_CALL_FAILED if the call to the conveyor \brief Change the current state of the system. Valid states are: stopped; running; paused. This method is used to change the current state of the system. Valid

main_control.h 3/19 main_control.h 4/19 states are: running, stopped, paused. The following defines the system when it is in each state: relinquish it, see next method), or ERROR_GRANT_CONTROL if something went wrong. STOPPED: the system is not feeding parts and currently has no part factories created. When the system transitions in to the stopped state, sub system thread must be paused and part specific factories deleted. The %queue of parts which the robot has yet to retrieve must also be flushed. \param thread_id Identifier of the thread that is requesting to control the feeder. \return 0 on success. SOMEONE_ELSE_HAS_CONTROL if some else already as control. ERROR_GRANT_CONTROL if something else went wrong. RUNNING: the system is actively retrieving parts from the feeder. When the system transitions to the running state from the stopped state, part specific factories need to be instantiated and the sub system threads then instructed to begin. This transition cannot take place if a part to feed has not been specified. PAUSED: the system is waiting to resume operation while in this state. The part specific factories are waiting to resume and the %queue of parts already located by the vision system and not yet retrieved by the robot is left intact. A second call to the change_system_operation with the pause request will cause the system to immediately resume operations. \par The %user must have control for this method to perform the requested action. The method returns a 0 on success, ERROR_NO_CONTROL is the %user didn t have control, and ERROR_SYSTEM_CALL_FAILED if the call to the conveyor server object failed. If the state change request was successfully, the method signals the update thread to send an update to all registered users before returning. /*! \fn int main_control::relinquish_control(dword thread_id) \brief Release control of the feeder. This method is used to let go of control if you already have it. It returns a 0 on success (you no longer have control) or ERROR_GIVE_UP_CONTROL if something went wrong. \param thread_id Identifier of the thread that is requesting to release control the feeder. Only the thread that currently has control may release control. \return 0 on success. ERROR_GIVE_UP_CONTROL if something else went wrong. /*! \fn void main_control::robot_update(int part_type, double time) \brief Causes a robot update message to be sent to all registered users. \param thread_id Identifier of the thread that is making the state change request. \param new_state The state into which the feeder is to transition. Valid states are: stopped; running; paused. \return 0 on success. ERROR_NO_CONTROL if the thread which made the request didn t have control. ERROR_SYSTEM_CALL_FAILED if the operation failed. This method is called by the robot sub system thread to report that a part has been retrieved. It lists the type of part which was retrieved (assuming that multiple parts are being fed) and the time taken by the robot in retrieving the part. \param part_type The type of part which was just retrieved. \param time The time spent by the robot is retrieving the part (in seconds). /*! \fn int main_control::set_part_type(dword thread_id, int new_part) \brief Select a new part to feed. \return None. /*! \fn void main_control::robot_update(double time) This method is used to identify the next part to be fed. This method only changes the part type if the system is in the stopped state. The general procedure for changing part type is to first stop the system, then call this method with the new part type, then start the system. The %user must have control for this method to perform the requested action. The method returns a 0 on success, ERROR_NO_CONTROL is the %user didn t have control, and ERROR_SYSTEM_CALL_FAILED if the call to the conveyor server object failed. If the call was successfully, the method signals the update thread to send an update to all registered users before returning. \brief Causes a robot update message to be sent to all registered users. This method is called by the robot sub system thread to report a part has been retrieved. This method is used if only a single type of part is being fed. The part type will then be assumed to the be the type define by the set_part_type method. \param time The time spent by the robot in retrieving the part (in seconds). \param thread_id Identifier of the thread that is making the part change request. \param new_part The ID of the part to be fed \return None. /*! \fn static int main_control::update_users(main_control *mc) \return 0 on success. ERROR_NO_CONTROL if the thread which made the request didn t have control. ERROR_SYSTEM_CALL_FAILED if the operation failed. /*! \fn int main_control::request_control(dword thread_id) \brief Static method which is run as a asynchronous thread that sends update messages to registered users. This static method is ran as a separate thread that sends updates to remote users. It runs asynchronously so that system performance is not hindered by the number of users. \brief Request to gain control of the feeder. This method is used to get control of the system. Until a %user has control, they may only \em watch the system. The method returns a 0 on success (the %user has control), a SOMEONE_ELSE_HAS_CONTROL if someone else already has control (the only way to lose control is to \param *mc Pointer to the main_control object. Needed so that the static method may access members of the main_control object. \return Should never return. The thread should be killed by the Destructor of the main_control class.

main_control.h 5/19 main_control.h 6/19 /*! \fn static main_control* main_control::instance() created when the %user logs in) constructs the message and send it (across a socket) to the %user s GUI. \brief Static method to get a pointer to the class. \return true on success. This method is used to get a pointer to the class. It follows the singleton design pattern so that only one instance of the object is ever created in the system. \return A pointer to the class on success, NULL on error. /*! \fn bool main_control::unregister_me(dword thread_id) \brief Un register a %user who is currently logged in an receiving system update message. /*! \fn int main_control::get_system_state() \brief Return the current control state of the system. This method returns the current state of the system. Current system states are Stopped, running, or paused. \return The states of the system is returned: STOPPED, RUNNING, or PAUSED This method un registers a %user who is currently logged in and receiving system update messages. It removes the %user from the registered %user data list. It uses the thread_id of the %user update thread (supplied at registration) to identify which %user to remove. \param DWORD thread_id The ID of the thread the %user used to register themselves with the register_me method. \return TRUE on success. /*! \fn int main_control::set_auto_engage(dword thread_id) /*! \fn static int main_control::retriever_system(main_control *mc) \brief Enable the auto adjustment functionality of the feeder. \brief Asynchronous thread which controls the actions of the %retriever. This method is used to engage the auto adjustment system for the part currently being fed. This change can only take place if the system is running (i.e. part factories have been created). The %user must also have control for this to happen. Once the feeder is under auto control, the %user may no longer adjust feeder parameters such as conveyor or robot speeds. \param DWORD thread_id The ID of the thread making the request to enable the auto adjustment mechanism. This is used to ensure the %user making the request actually has control. \return 0 on success. SYSTEM_NOT_RUNNING or SOMEONE_ELSE_HAS_CONTROL on error. This is one of the four asynchronous client threads which operate when the system is running. The thread may be in one of the three system states (STOPPED, RUNNING, or PAUSED). The thread simply loops and performs a simple action if in the RUNNING state, otherwise it simply sleeps for a while (1 second) before cycling again. Each time through the loop, it checks the current state the main_control object wants it to be in and changes it operation if necessary. When the system is shutdown, the thread exits. The thread does NOT exit when the %user stops feeding the current part. \param *mc Pointer to the main_control object. It is necessary to pass a pointer to the object because the method is static and cannot otherwise access the methods data. /*! \fn bool main_control::control(dword thread_id) \brief Tells if the %user has control. \return Shouldn t return until the system is shutdown and it exits. /*! \fn static int main_control::locator_system(main_control *mc) This method is used to tell if the requesting %user currently has control. \brief Asynchronous thread which controls the actions of the %locator. \param DWORD thread_id The ID of the %user for whom the current status of control is to be determined. \return true if the %user has control. false if the %user does not have control. /*! \fn bool main_control::register_me(dword thread_id, message_queue *mq) \brief Register a %user who has already logged in to receive notification updates. This method registers a %user (creates the appropriate structures in the registered %user data list) to receive system updates. Each time the system sends out an update (either system change or robot), the list of users is consulted to ensure all users receive an update. Once a %user has registered, they will continue to receive updates till they un register. \param DWORD thread_id The ID of the %user who wishes to receive update. \param message_queue *mq A pointer to the message %queue into which to place updates to the %user. The users personal thread (which is This is one of the four asynchronous client threads which operate when the system is running. The thread may be in one of the three system states (STOPPED, RUNNING, or PAUSED). The thread simply loops and performs a simple action if in the RUNNING state, otherwise it simply sleeps for a while (1 second) before cycling again. Each time through the loop, it checks the current state the main_control object wants it to be in and changes it operation if necessary. When the system is shutdown, the thread exits. The thread does NOT exit when the %user stops feeding the current part. \param *mc Pointer to the main_control object. It is necessary to pass a pointer to the object because the method is static and cannot otherwise access the methods data. \return Shouldn t return until the system is shutdown and it exits. /*! \fn static int main_control::positioner_system(main_control *mc) \brief Asynchronous thread which controls the actions of the %positioner. This is one of the four asynchronous client threads which operate when the system is running. The thread may be in one of the three system states (STOPPED, RUNNING, or PAUSED). The thread simply loops

main_control.h 7/19 main_control.h 8/19 and performs a simple action if in the RUNNING state, otherwise it simply sleeps for a while (1 second) before cycling again. Each time through the loop, it checks the current state the main_control object wants it to be in and changes it operation if necessary. When the system is shutdown, the thread exits. The thread does NOT exit when the %user stops feeding the current part. \param *mc Pointer to the main_control object. It is necessary to pass a pointer to the object because the method is static and cannot otherwise access the methods data. \return Shouldn t return until the system is shutdown and it exits. /*! \fn static int main_control::auto_adjuster_system(main_control *mc) \brief Asynchronous thread which controls the actions of the %auto_adjuster. This is one of the four asynchronous client threads which operate when the system is running. The thread may be in one of the three system states (STOPPED, RUNNING, or PAUSED). The thread simply loops and performs a simple action if in the RUNNING state, otherwise it simply sleeps for a while (1 second) before cycling again. Each time through the loop, it checks the current state the main_control object wants it to be in and changes it operation if necessary. When the system is shutdown, the thread exits. The thread does NOT exit when the %user stops feeding the current part. /*! \fn double main_control::get_inc_percentage() \brief Return the current speed of the inclined conveyor as a percentage of the speed of the horizontal conveyor. This method is used to retrieve the current setting of the speed of the inclined conveyor. The value returned is the speed of the conveyor as a percentage of the horizontal conveyor. \return Inclined conveyor speed: percentage of the horizontal speed. /*! \fn int main_control::get_robot_speed() \brief Return the current speed of the robot (percentage of max). This method is used to retrieve the current setting of the speed of the robot. The value returned is a percentage of the maximum speed. The maximum speed is between 0% and 200%. Speeds greater than 100% increase physical robot speed by smaller and smaller amounts (not linearly related to the percentage) at the expense of accuracy and control. \par The actual speed of the robot is a combination of the monitor speed and the program speed. This simply returns the program speed. \return Speed of the robot as a percentage of maximum. \param *mc Pointer to the main_control object. It is necessary to pass a pointer to the object because the method is static and cannot otherwise access the methods data. \return Shouldn t return until the system is shutdown and it exits. /*! \fn void main_control::refresh_subsystem_state(void) \brief Update the sub system state. Basically the speeds of the robot and conveyors. /*! \fn void main_control::print_state(char *from_where) Update the sub system state. Basically the speeds of the robot and conveyors. \brief Print out the current state of the system. Used for debugging. This method is used to print out the current state of the system. This includes all relevant information about the system. It is formatted nicely to make reading easier. Used for debugging when you really need to know what the system is up to. \return None. /*! \var static main_control* main_control::main_control_instance \brief Static pointer to the constructed object. Used in the singleton construct. \param from_where Character string into which may be placed the name of the method (or some other useful string) from which the method is called. Helpful if you are printing out the state from several places in the code. \return None. /*! \fn void main_control::print_user_list() \brief Print out the list of current users (thread_id values are printed). This method prints out the list of users who are currently logged in. Useful for debugging. /*! \var static Semaphore_open main_control::guard_mutex \brief Semaphore used in the double check guard form of the singleton construct. /*! \var robot_motion_server* main_control::robot \brief Pointer to the robot motion server. /*! \var conv_server* main_control::cnv \brief Pointer to the conveyor motion server. \return None. /*! \fn double main_control::get_hor_speed() /*! \var part_factory* main_control::factory \brief Pointer to a part factory abstract base class. \brief Return the current speed of the horizontal conveyor in \f$\frac{mm{sec\f$. This method is used to retrieve the current setting of the speed of the horizontal conveyor. The value returned is \f$\frac{mm{sec\f$. This is a pointer to a type %part_factory. At run time, when the %user selects a part, the concrete implementation f that particular factory is created and this pointer then points to it. The variable is defined as a the abstract base type so it may point at any concrete factory implementation. \return Horizontal conveyor speed: \f$\frac{mm{sec\f$. /*! \var HANDLE main_control::update_users_thrd

main_control.h 9/19 main_control.h 10/19 \brief Handle to the users update thread returned from the create thread call. Used when killing the thread. /*! \var DWORD main_control::update_users_thrd_id \brief ID of the users update thread. Also returned from the create thread call. to determine what it is suppose to do this time through the loop. It sets locator_thread_state when performing the desired function to indicate to the main control object that it is in the requested state. /*! \var int main_control::locator_thread_state \brief The state the %locator thread is in. /*! \var HANDLE main_control::retriever_thread \brief Handle to the %retriever thread returned from the create thread call. Used when killing the thread. The main control object sets locator_thread_state to indicate which state to be in. The %locator thread then sets this variable when executing to indicate to the main control object that it is in the state requested. Main control may monitor this variable for an indication of the current state of the thread. /*! \var DWORD main_control::retriever_thread_id /*! \var locator* main_control::locator_factory \brief ID of the retriever thread. Also returned from the create thread call. /*! \var int main_control::retriever_system_state \brief The state the main control wants the %retriever to be in. \brief Pointer to an abstract locator factory. At run time, when the %user selects a part type, a concrete implementation of a %locator will be created. This pointer will point at that object. It is defined as the abstract base type so that it may validly point at any concrete implementation of a %locator. This is the state the main control object wants the %retriever to be in. The %retriever thread reads this variable in a switch statement to determine what it is suppose to do this time through the loop. It sets retriever_thread_state when performing the desired function to indicate to the main control object that it is in the requested state. /*! \var int main_control::retriever_thread_state \brief The state the %retriever thread is in. /*! \var HANDLE main_control::positioner_thread \brief Handle to the %positioner thread returned from the create thread call. Used when killing the thread. /*! \var DWORD main_control::positioner_thread_id \brief ID of the positioner thread. Also returned from the create thread call. The main control object sets retriever_thread_state to indicate which state to be in. The %retriever thread then sets this variable when executing to indicate to the main control object that it is in the state requested. Main control may monitor this variable for an indication of the current state of the thread. /*! \var retriever* main_control::retriever_factory \brief Pointer to an abstract retriever factory. At run time, when the %user selects a part type, a concrete implementation of a %retriever will be created. This pointer will point at that object. It is defined as the abstract base type so that it may validly point at any concrete implementation of a %retriever. /*! \var int main_control::positioner_system_state \brief The state the main control wants the %positioner to be in. This is the state the main control object wants the %positioner to be in. The %positioner thread reads this variable in a switch statement to determine what it is suppose to do this time through the loop. It sets positioner_thread_state when performing the desired function to indicate to the main control object that it is in the requested state. /*! \var int main_control::positioner_thread_state \brief The state the %positioner thread is in. /*! \var HANDLE main_control::locator_thread \brief Handle to the %locator thread returned from the create thread call. Used when killing the thread. The main control object sets positioner_thread_state to indicate which state to be in. The %positioner thread then sets this variable when executing to indicate to the main control object that it is in the state requested. Main control may monitor this variable for an indication of the current state of the thread. /*! \var DWORD main_control::locator_thread_id /*! \var positioner* main_control::positioner_factory \brief ID of the locator thread. Also returned from the create thread call. /*! \var int main_control::locator_system_state \brief The state the main control wants the %locator to be in. \brief Pointer to an abstract positioner factory. At run time, when the %user selects a part type, a concrete implementation of a %positioner will be created. This pointer will point at that object. It is defined as the abstract base type so that it may validly point at any concrete implementation of a %positioner. This is the state the main control object wants the %locator to be in. The %locator thread reads this variable in a switch statement /*! \var HANDLE main_control::auto_adjuster_thread

main_control.h 11/19 main_control.h 12/19 \brief Handle to the %auto_adjuster thread returned from the create thread call. Used when killing the thread. /*! \var DWORD main_control::auto_adjuster_thread_id \brief ID of the auto adjuster thread. Also returned from the create thread call. /*! \var int main_control::auto_adjuster_system_state \brief The state the main control wants the %auto_adjuster to be in. \brief Monitor to control access to the control system variable. Since multiple users may be logged in at any one time and each %user has their own asynchronous thread, it would be possible for two users to simultaneously request control. If there was an unfortunate swapping out of tasks, it might be possible due to the race condition for both users to gain control (only one would actually have control, the other would only \em think they had control). This monitor provides atomic access to the control variable to prevent this problem. /*! \var message_queue* main_control::update_users_queue This is the state the main control object wants the %auto_adjuster to be in. The %auto_adjuster thread reads this variable in a switch statement to determine what it is suppose to do this time through the loop. It sets auto_adjuster_thread_state when performing the desired function to indicate to the main control object that it is in the requested state. /*! \var int main_control::auto_adjuster_thread_state \brief The state the %auto_adjuster thread is in. \brief Queue into which system state update messages are placed. The update users thread creates a %queue into which the rest of the main control tasks places updates to users. The %user update thread then pulls updates from this %queue and send the to all registered users. This is another layer of insulation between the unpredictability of the network and the soft real time needs of the main control object. /*! \var parts_queue* main_control::pq The main control object sets auto_adjuster_thread_state to indicate which state to be in. The %auto_adjuster thread then sets this variable when executing to indicate to the main control object that it is in the state requested. Main control may monitor this variable for an indication of the current state of the thread. \brief Pointer to the parts %queue used to pass part locations between the %locator and %retriever threads. /*! \var timer* main_control::up_timer /*! \var auto_adjuster* main_control::auto_adjuster_factory \brief Pointer to an abstract auto_adjuster factory. \brief Timer to record how long the system has been up. /*! \var timer* main_control::pause_timer At run time, when the %user selects a part type, a concrete implementation of a auto_adjuster will be created. This pointer will point at that object. It is defined as the abstract base type so that it may validly point at any concrete implementation of a auto_adjuster. \brief Time to record how long the system has been in a paused state. /*! \var timer* main_control::run_timer /*! \var bool main_control::construction_failed \brief Timer to record how long the system has been feeding parts (also used in computing the current ppm). \brief Boolean to indicate if the constructor for the class failed. /*! \var Monitor* main_control::user_list \brief %Monitor to control access to the %user list. /*! \var char main_control::sys_update_str[msg_str_max_len] \brief String which holds the message which gets passed to the %user update thread to indicate a system update to all users should be performed. It is important that the list of current users not become corrupt. This monitor provides atomic access to the list. /*! \var Monitor* main_control::robot_data_lock When this type of message is received by the %user update thread, it sends an update that includes all system statistics back to the users. This include current parameter setting for the conveyors, robot, and timers. Since this is a lot of data, it is only performed when one of the values actually change. \brief %Monitor to control access to the robot data structure. A special data structure is used to enable the robot to pass information about the last part retrieved back to the main control object for data logging and reporting to the users. This data structure allows the robot to quickly relay that data and not to get hung up waiting for main control to do something. Main control acquires this lock only long enough to copy the data out to its only local structures. This is to prevent the robot thread from becoming stuck waiting for main control to get house keeping style tasks done. E.g. we wouldn t want the robot waiting because of network traffic. /*! \var Monitor* main_control::control_lock /*! \var char main_control::robot_update_str[msg_str_max_len] \brief String which holds the message which gets passed to the %user update thread to indicate a robot update should be sent to all users. Each time the robot retrieves a part, the system send an update to the users indicating what type of part was fed, and the current timers and throughput. This happens each time a part is fed, so the complete system state is not sent. /*! \var char main_control::robot_update_no_part_str[msg_str_max_len]

main_control.h 13/19 main_control.h 14/19 \brief String which holds the message which gets passed to the %user update thread to indicate that a robot no part fed update should be sent to all users. It is sometimes necessary to send a robot update even when the robot hasn t retrieved apart (when wanting to update the timers on the users GUI, for example). This send an update without trying to update part fed information. Old values are used. /*! \var char main_control::yaxis[2] \brief String which holds the string passed to the conveyor server to indicate the inclined conveyor. /*! \var char main_control::xaxis[2] \brief String which gets passed to the conveyor server to indicate the horizontal conveyor. /*! \var robot_update_data* main_control::rud \brief Pointer to the robot update object. /*! \var user* main_control::user_list_head \brief Pointer to the first %user on the registered %user list. /*! \var system_state* main_control::sys_state \brief Current state of the system: STOPPED, RUNNING, or PAUSED. /*! \class main_control::user \author Greg Causey \date 1/28/01 \brief Object which represents a registered %user. \par Revision History The following revisions have been made to the class. \par Description: This object is used to represent a registered %user. When a %user logs in, a new object is created to hold the users ID, a and a pointer to a message %queue into which to place messages to the %user. /*! \fn main_control::user::user() \brief Create a generic %user. ID = 0, Pointer to message %queue = NULL, pointer to next %user = NULL. \return None. /*! \fn main_control::user::user(message_queue *MQ, DWORD ID) \brief Create a new user object. \brief Destructor. /*! \var DWORD main_control::user::id \brief id The ID of the %user the object represents. /*! \var message_queue* main_control::user::mq \brief Pointer to the message %queue into which to place update messages to the %user. /*! \var main_control::user* main_control::user::next \brief Pointer to the next registered %user. NULL if this is the last registered %user in the linked list. /*! \class main_control::system_state \author Greg Causey \date 1/28/01 \brief Object which holds the current state of the system. \par Revision History The following revisions have been made to the class. \par Description: This class is used to hold the current state of the system. This provides a single object which can be consulted to determine any information about the system. /*! \fn main_control::system_state::system_state() \brief Constructor. Initials the system state to a consistent state. /*! \fn main_control::system_state::~system_state() \brief Destructor. /*! \var main_control::system_state::inc_percent \brief Current speed of the inclined conveyor. \par Description: The current speed of the inclined conveyor. This value is listed as a percentage of the speed of the horizontal conveyor. Since the relative speed of the to conveyors is important to the operation of the system, specifying this speed as a percentage of the horizontal speed seemed a more logical way of determining the speed; rather than specifying the speed independently. the valid range for this parameter is 0% 200%. /*! \var main_control::system_state::hor_speed \brief Current speed of the horizontal conveyor in \f$\frac{mm{sec\f$. \param *MQ Pointer to the message %queue into which to place update messages. \param ID The ID (thread ID) of the registered %user. \return None. This is the current speed of the horizontal conveyor. It is listed in \f$\frac{mm{sec\f$. The valid range for this parameter is 0 400 \f$\frac{mm{sec\f$. /*! \var main_control::system_state::robot_speed /*! \fn main_control::user::~user() \brief Current speed of the robot. The current speed of the robot. It is listed as a percentage of the