Communication between Robots and a Computer via the Internet Final Report Andreas Bernhard Max Hofmeier v0.5 second alpha Submission Date: 26.04.2005 Student ID: 2406108 This report has been submitted for assessment towards a Bachelor of Engineering De- gree in Computer Systems and Networks (2388) BEng in the School of Engineering, South Bank University. This report is written in the author's own words and all sources have been properly cited. Author's signature: 1 Acknowledgements I would like to thank my supervisor, Dr. Shuwo Chen, who was always ready to answer my questions and support me with my project. Thanks also to all the people which were involved in my project. There was Dr. Chris Merridan, the technical assistant and Dr. Sang ???, who supports me by dealing with the robot. Another thanks go to all people and organisations which supported me and my studies. Dr. Thomas Risse who helps me to organise of my overseas-term. My German class mates, which are stood on my side with advice and encourage- ment. All peoples which were providing help in form of materials such as free software (GNU Linux), free documents (web-sites), articles, and books. The Lon- don South Bank University and the University of Applied Science Bremen, on which I studied. Contents 1 Introduction 1 2 Aim and Objectives 2 2.1 Aim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2.2 Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 3 Deliverables 2 4 Technical Background and Context 3 4.1 Modes to Control a Robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 4.1.1 Direct Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 4.1.2 Supervisory Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4.1.3 Job Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4.2 Levels of Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 4.3 Adaptability of the Program which Controls the Robot . . . . . . . . . . . . . . . 5 4.4 Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 4.5 Real Time and Bandwidth Constrains . . . . . . . . . . . . . . . . . . . . . . . . 7 4.5.1 How the Internet Works . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 4.5.2 Changing Behaviour and Delay . . . . . . . . . . . . . . . . . . . . . . . . 9 4.5.3 Carrier Sense Multiple Access with Collision Detection . . . . . . . . . . . 9 4.5.4 Level to Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 4.5.5 Monitor the Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 4.5.6 Buffer to Compensate Random time Delay . . . . . . . . . . . . . . . . . 10 4.5.7 Use a Simulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 4.6 Safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 4.7 The Reason for this Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 5 Technical Approach 12 5.1 The Ping Measurement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 5.1.1 Ping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 5.1.2 Source ­ Destinations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 5.2 Basic Concept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 5.3 Implementation of the Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 5.3.1 Network Layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 5.3.2 Usage of the Linux Network Implementation . . . . . . . . . . . . . . . . 15 5.3.3 Block Transfer Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 5.3.4 Line Monitoring Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 20 5.3.5 Authentication? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.4 Demonstration with a Real Robot . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.4.1 The Robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.4.2 Hardware-Interface to the Robot . . . . . . . . . . . . . . . . . . . . . . . 22 5.4.3 Software-Interface to the Robot . . . . . . . . . . . . . . . . . . . . . . . . 25 5.4.4 GUI and Simulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 6 Results and Discussion 28 6.1 Analyse of the Ping Measurement . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 6.2 Result of the Ping Measurement . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 6.3 Test of the Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 6.3.1 Basic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 6.3.2 Block Transfer Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 6.3.3 Line Monitoring Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 33 6.4 Test of the Interface to the Robot . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 6.4.1 Hardware-Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 6.4.2 Software-Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 6.5 Test of the GUI and the Simulator . . . . . . . . . . . . . . . . . . . . . . . . . . 35 7 Conclusions and Recommendations for Further Work 36 7.1 Project Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 7.2 Personal Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 7.3 Recommendations for Further Work . . . . . . . . . . . . . . . . . . . . . . . . . 38 8 Bibliography and References 39 9 Project Planning 43 9.1 Work Breakdown . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 9.2 Action Plan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 9.3 Milestones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 9.4 Project Schedule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 10 Appendices 46 10.1 User's Manual GUI for Robot and Server . . . . . . . . . . . . . . . . . . . . . . 46 10.1.1 Both Programs (guirobot and guiserver) explained . . . . . . . . . . . 46 10.1.2 Manipulate the Position of the Robot's Platform . . . . . . . . . . . . . . 48 10.1.3 Stopping the Robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 10.1.4 Starting both Programs, Parameter . . . . . . . . . . . . . . . . . . . . . 48 10.2 API of the Network Library (libcomm) . . . . . . . . . . . . . . . . . . . . . . . . 49 10.3 Source Code of the Network Library (libcomm) . . . . . . . . . . . . . . . . . . . 63 10.3.1 src/lib/libcomm.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 10.3.2 src/lib/libcomm.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 10.4 API of the Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 10.5 Source Code of the Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 10.5.1 src/example/interface.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 10.6 Source Code of the GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 10.6.1 src/example/guicommon.c . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 10.6.2 src/example/guirobot.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 10.6.3 src/example/guiserver.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 10.7 Source Code of the Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 10.7.1 src/test/test001sockets.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 10.7.2 src/test/test002integer.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 10.7.3 src/test/test003block.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 10.7.4 src/test/test004md5.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 10.7.5 src/test/tes005realtime.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 10.7.6 src/example/test001interface.c . . . . . . . . . . . . . . . . . . . . . . . . 125 Abstract This report describes the final year project of Andreas Hofmeier which aimed at developing the software tool for the remote control of robots over the Internet. The feasibility of using the Internet to control robots was studied with the result that it is possible under certain restrictions. Different approaches to bypass these restrictions were analysed and one of them was implemented. Within this project a software platform in form of a library for GNU Linux was developed to provide the necessary tools. For demonstration purposes an example system to control a simple robot was implemented based on the function of the library. A. Hofmeier, Final Year Project: Final Report 1 1 Introduction Robots become more and more important because the technical progress allows economic and useful applications. Controlling robots over short distances with cable or wireless is not longer a problem, but more often robots need to be controlled far away. For example a robot as security guard or a pizza-robot is operating at home while controlled from the office. For this demand a public communication network has to be used. One of the most flexible and economical possibilities is the Internet which works packet-oriented. All data has to be fragmented before it can be transfered. The transfer-process within the Internet can be compared with the postal service (Ball et al. 1999). "The packet should be there within two days" is a possible answer if the post clerk is asked how long the packet takes. This little word "should" is the problem. It should, but there is no guarantee. If many packets are handed in, it may take a week to deliver the packet. The Internet has the same problem even if a packet does not need a week, it cannot be predicted how long a packet takes to be delivered. Because of this random time delay the Internet has limits to which it can provide a platform to control robots (Elhaji et al. 2000). Within this project the feasibility of remote control of robots over the Internet was studied and a software platform on GNU Linux which provides this feasibility was developed. This platform in from of a network library tries to provide a tools to use the Internet to control a robot. An example of using this network library is given by a simple demonstration on a real robot. This demonstration includes a user interface, a simulator, and an interface to the robot. The analyses of the possibility to use the Internet to control robots led to the result that this is possible under some circumstances. One of this possibilities were implemented: the line monitor. This tool observes the network connection and initiates appropriate actions if the line (connection) becomes unusable for the remote controlling purpose. The report is structured in this way: the following two sections define the aim, the objectives, and the deliverables of the project. The next section introduces the technical background. After this the technical approach will be explained in detail. The results of the analyses and the tests are given in the next section named "Results and Discussion". Before the Bibliography is stated conclusions and recommendations for further work are given. This is followed by details about the planning of the project compared with its realisation. The last parts of A. Hofmeier, Final Year Project: Final Report 2 the report are the appendices which include the software and its documentation (user's manual and application programmer interface). 2 Aim and Objectives 2.1 Aim The aim of the project is to develop a software platform on GNU Linux systems (in the form of a library) for the communication between a server and robots to realise remote control of robots over the Internet. The communication between robots is allowed as well. 2.2 Objectives 1. (a) Feasibility study of real-time control of robots on the Internet. (b) Establishment of realistic levels according to the Internet overloading (c) Block diagram of the architecture of the software platform 2. (a) Developing the library (b) Developing the simulator and the user interface (UI) (c) Demonstrating the platform by using a simulation. Showing that it is possible to control the simulated robot over an Internet connection. 3. (a) Developing an interface to the real robot (b) Demonstrating the platform by means of the real robot. Showing that it is possible to control the real robot over an Internet connection. 3 Deliverables 1. The Library (the Software Platform) 2. Documentation of the Library (API; description of the functions; how to use) 3. User Interface A. Hofmeier, Final Year Project: Final Report 3 4. Documentation of the User Interface (User manual) 5. Simulator 6. Documentation of the Simulator (User manual) 7. Interface between Library and real Robot, for Demonstration. 8. Interim Report 9. Presentation 10. Final Report 4 Technical Background and Context 4.1 Modes to Control a Robot Han et al (2004) distinguishes between three modes to control a robot which were adapted. This three points are extreme examples only. A robot in the "real world" will be somewhere between those extreme points. This depends highly on the application. 4.1.1 Direct Control Within this control mode the hardware is controlled at lowest level over the network. There is no intelligence or data processing on the robot's side. For example: the robot receives a bit stream which represents its outputs. The robot receives a package on n bits analogous to n output-bits. These outputs can be simple actors which can only be switched on or off (one bit) or complex solutions with digital-to-analogue converters which are controlling a DC-motor (maybe 12 bits). This mode requires strict time constraints because the controlling is time based. If the robot should move one meter in a direction the corresponding motor for this direction has to be switched on for exactly the time which is necessary to cover this distance. If the motor is switched on longer the robot will cover a greater distance and vise versa. The engines has to be switched"in time"but this is almost impossible if the time for transmitting a bit (or a package if more than A. Hofmeier, Final Year Project: Final Report 4 one motor has to be controlled) varys from one command to the next one. If the time-delay was constant, it could be simply subtracted in the calculation. Another problem occurs if the connection breaks down. When the robot receives a "start moving" command just before the connection fails it may move until the battery is empty. This can be a hazard if, for example, the robot hits someone. 4.1.2 Supervisory Control This control mode controls the robot on a much higher level. For this reason more intelligence is needed on the robot's side. A target is transmitted to the robot. The robot has to evaluate this target and calculate the appropriate action to reach it. The target can be transmitted in relative (x, y) or in in absolute (x, y) coordinates (In this case it is assumed that the robot has two degrees of freedom ­ can move in two dimensions.) In the first case the robot has to calculate which actors have to be switched on and for how long to cover the given distance in the right direction. In the second case the robot has to know its current position to calculate the x and the y which can be used to move to the target. The calculation of x and y may include considerations like: · What is the fastest way? · What is the way which needs the fewest resources (energy)? · Which way causes no hazards or damages? Are they any hindrances? In this mode the time constraints are not as strict as in the direct control because the robot will stop moving if it reaches its target and does not receive new targets in time. Normally hazards only occur if something is moving or is "in action". 4.1.3 Job Scheduling Within the Job Scheduling Mode a whole sequence of targets or jobs is transmit- ted to the robot at once. A. Hofmeier, Final Year Project: Final Report 5 4.2 Levels of Processing To be able to "teleoperate" something (for example to control a robot from far away) at least three levels of data-processing are necessary. These three levels are the Human Operator, the User Interface (UI) and the Robot Control Program. They are illustrated in Figure 1. USER Human Operator UI User Interface Robot Control Program Technical System On this point a computer network is used which causes the random time delay. Figure 1: Different Levels of Processing which are necessary to Control a Robot Remotely. · The Human Operator makes the decisions and gives the system its purpose. There will be no systems without a human operator at some level because there is no point in doing something without gaining an advantage. This human operation can be within a wide range from "switching it on to get a cup of hot coffee out of it" to "control a space-explore-robot to explore what is out there". The human operator always gives the commands to an User Interface. · The User Interface has to read the commands from the user and transmit it through some kind of network to the robot-control-program. The pro- gram which performs the necessary operations to handle this job runs on computer in front of the user. This can be a kind of robot-control-server if it is taken as a central control station. · The Robot-Control-Program receives the commands from the User Interface and applies them to the hardware of the robot. This job is done by a piece of software which runs on a computer on (or near to) the robot. 4.3 Adaptability of the Program which Controls the Robot In these days the requirement of multi-functionality becomes more important. The robot should be as flexible as possible to be used in a wide spectrum of applications. A. Hofmeier, Final Year Project: Final Report 6 To use a robot for a new application the program which controls it has to be changed. As discussed above this program is made up of three components. (If it is assumed, that there is some kind of "program" in our brain.) In case that the "Technical System" is very primitive it may be enough to train the human operator to do other things with it. An example could be a simple remote control of a crane which switches actors remotely. An important improvement of our technology today is that it helps us to perform our tasks. The time of a human operator is valuable and should not wasted in doing things which can be done by a computer. Many calculations can be processed much faster and more accurate by a computer than a human. The consequence of this is that it may not be enough to train the human operator to do new things with the robot. In this case two components are left: The GUI1 (Server) and the Robot-Control-Program. One solution is to keep the robot-control-program as simple as possible and trans- fer all intelligence into the GUI (the Server). In this case the Direct Control is in use. As discussed this can be a problem because of safety considerations. If the network link breaks down no server or human operator can stop the robot. There must be some processing on the robot's side. At least an emergency stop function has to be implemented. This solution makes it possible to change the behaviour of the technical system only by changing the server/GUI side. This can be an advantage. On the other hand it is possible to perform one part of the processing on the robot's side. This moves the classification of the system closer to the Supervisory Control. The GUI/Server transmits a job or a target to the robot and monitors its execution. It might be necessary to change both, the GUI/Server and the robot- control-program in order to change the behaviour of the system. Advantages of this solutions are: distribution of processing work on both sides, probably less bandwidth requirements, and a possible gain in safety. 4.4 Feedback Another important issue needs to be considered: the feedback. This is the dif- ference between operating or affecting something and controlling it. Affecting means to do something without getting a response. There is no guarantee that 1 GUI stands for Graphical User Interface. A. Hofmeier, Final Year Project: Final Report 7 everything happens the way as it was intended to happen. Controlling applies a feedback which closes this (response-)loop. For example, it can be seen what the robot does. In this case it is likely that the bandwidth of the feedback connection is much bigger than the control connection because of the video data. Figure 2 illustrates this example. Unfortunately these terms are often confused. In this report the word "controlling" is used for both. USER Human Operator UI User Interface Robot Control Program Technical System On this point a computer network is used which causes the random time delay. Figure 2: Different Levels of Processing which are necessary to Control a Robot Remotely: A Closed-Loop-System with Feedback. 4.5 Real Time and Bandwidth Constrains The term"real time"is used for systems which have to complete a task in a certain time. This time depends on the application but it can be said that the (reaction- )time must be short enough to perform an in-time control of the environment. In this case the transfer of data over a network has to be finished within a certain time-limit. Bandwidth describes how much data a network is able to transfer in a certain time. The time delay will increase if more data is transmit because the data has to be buffered until the line is free. If continuously more data is transfered the network can no longer transfer all the data without loosing some of it. Both terms are interdependent. This will be explained in the following section. 4.5.1 How the Internet Works Before it is possible to explain what the problem causes it is necessary to provide an overview about "how it works". If detailed information is requested please refer to a textbook, for example, Forouzan (2001) from which this overview was condensed. A. Hofmeier, Final Year Project: Final Report 8 Application Layer Presentation Layer Session Layer Transport Layer Network Layer Data Link Layer Physical Layer OSI-Model Internet Application uses TCP-Socket-Streams or UDP-Sockets TCP UDP IP MAC/Ethernet Hardware }}} GET /an-h/en/papers/lsbu/ HTTP/1.1 Host: www.lgut.uni-bremen.de User-Agent: Mozilla/5.0 Galeon/1.2.9 (X11; Linux) Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66 Keep-Alive: 300 Connection: keep-alive Accept: image/png,image/jpeg,image/gif Referer: http://www.an-h.de/an-h/ If-Modified-Since: Wed, 26 Jan 2005 20:00:21 GMT If-None-Match: "c012-d2-41f7f6d5" Cache-Control: max-age=0 HTTP-Request in Protocol Data Units segment datagramm frame bit/signal stream 01101001100010110101 - Header } (PDUs) Figure 3: Comparison between OSI-Model and the real Internet Figure 3 shows an overview of the different levels of data-processing which have to be passed before a communication is possible. The diagram illustrates these levels on a Hyper Text Transfer Protocol (HTTP) request. Those requests are generated if a web-page is opened. In the case of the example is was http://www.lgut.uni-bremen.de/an-h/en/papers/lsbu/. To understand the idea behind these levels of layers it can be compared of as telling someone a long story who is on the other side of the world. The narrator (the application) starts writing it and gives the script its secretary (the transport layer). She knows that the postal service accepts letters up to a maximum of 80g. For this reason the story has to be segmented into pieces which fit on less than 80 grams of paper. In order to make it easier to recombine the story on the other side of the world, supporting information like a segment-number is added to each letter. This letter is given to the next secretary (the Network Layer). In this step the letter will be placed in an envelope. This envelope on which the source and destination address is written will be handed in to the nearest post office (the Data Link Layer). Within the post office the letter will be packed into a bag which is transported to another post office. This office may resort the bags and send it to the following post office. This process (which can be compared with the routing and transferring data over a line [Physical Layer]) will be continuing until the letter reaches the mail box of the receiver. Then the reverse process takes place. A. Hofmeier, Final Year Project: Final Report 9 4.5.2 Changing Behaviour and Delay The problems which arise from this process are: the system must work transpar- ently. That means that the higher levels do not know what the lower levels are doing. For this reason the behaviour of the lower levels may vary. An example for this is a replacement of one secretary. The same problem occurs during the transport. There is no guarantee that the letter will always take the same route. It is unknown which way a letter will take. This depends on the environment and on the network load or utilisation. If, for example, an earthquake destroys a road, the mail must take another way. The workload of the system may change faster than the environment. During the rush-hour it takes longer to cover a distance than on a "normal" daytime. This can be compared with school hours ­ all students using the network. This both phenomena cause the Random Time Delay. 4.5.3 Carrier Sense Multiple Access with Collision Detection The next problem arises from the way in which the Physical Layer transmits data. Ethernet is used in most of the end-user networks of the Internet. Carrier Sense Multiple Access with Collision Detection (CSMA/CD) is in use within Ethernet. This protocol tries to broadcast when nobody else is sending data. If the network load increases it becomes harder to find a gap to send the data. Because of physical limitations (transmission speed) computers do not recognise fast enough if data is sent and start sending by them selfs. This causes collisions. Data is destroyed and has to be sent again. Because of this the delay increases with rising workload. These both are reasons for the unpredictability of the transport time. This is not applicable to modern switching networks. 4.5.4 Level to Use To use the high-level Transmission Control Protocol (TCP) or the User Datagram Protocol (UDP) to control robots is not the most efficient way. It is possible to bypass the official Transport Layer by replacing it with an own protocol that is optimised for Real Time Traffic. Liu et al (2004), for example, developed the "trinomial protocol". This is a semi-real-time-protocol. It works much better than the TCP or UDP but it cannot change the lower levels. These levels have to be used if the Internet should transport the data. They are prescribed by the Internet itself as a standard. A. Hofmeier, Final Year Project: Final Report 10 4.5.5 Monitor the Line Another possibility is to observe the network-connection and take appropriate actions if the connection becomes unusable for the purpose of remote controlling. This strategy assumes that the network is normally usable for the job. Without any further actions this method is not well suited for Direct Control. Instead it is very suitable for an additional usage. 4.5.6 Buffer to Compensate Random time Delay Andreu et al (2004) explored the possibility of using a buffer or a stack as a"Delay Regulator" to smooth up the random component of the transport delay. This is done by delaying the data on the receiver side (buffer) in a way that the overall delay stays constant. For example, if one command has to be processed in one second, one command per second has to be ready for processing on the robot's side. Assuming the maximal time delay for the transmission is 5 seconds, the sender starts transmitting 5 seconds before the robot starts executing commands. All data that is received earlier will be stored in a buffer. If the sender sends one command in one second, the robot reads one command a second from the buffer, and the maximal time-delay does no exceed 5 seconds, the commands are constantly delayed by 5 seconds. This is the way to suppress the random component of the time delay by extending the delay to a maximal value. This solution is suited to be used for direct control but has the disadvantage that the transmission takes longer than necessary. If everything works well all commands are delayed by the same time. It makes sense to combine this solution with a line-monitor to take appropriate actions if the maximal delay is exceeded. 4.5.7 Use a Simulator One idea to fit a robot-control-system into existing bandwidth constrains is to pre- vent the large bandwidth-consumption of the video-data-stream by using a simu- lator. This simulator simulates the environment of the robot on the GUI/Server side. Figure 4 gives an example of this. (Belousov, 2004; Han et al, 2001) A. Hofmeier, Final Year Project: Final Report 11 USER Human Operator UI User Interface Robot Control Program Technical System Simulator On this point a computer network is used which causes the random time delay. Figure 4: Different Levels of Processing which are necessary to control a Robot remotely: A Closed-Loop-System with Feedback through a Simulator. This solution makes a simulation of the reality necessary. However, the best sim- ulation is still just a simulation and not reality itself. For this reason reality and simulation may differ. Maybe the physical attributes of an object are calculated in a wrong way or the feedback is not accurate enough and an object is pictured in an other place than it really is. This can be a safety risk which has to be considered. 4.6 Safety According to the British Standard (1992) Industrial robots ­ Recommendations for safety, a single point of failure must not cause any hazards. For this reason it is very important to stop the robot if the network link breaks down. The technique of monitoring the line is well suited to this application. 4.7 The Reason for this Project This project was done to explore the Why this project Contribution "A Linux system can actually be adapted to work with as little as 256 KB ROM A. Hofmeier, Final Year Project: Final Report 12 and 512 KB RAM." (Addison, 2001) This network library has to run on such small embedded GNU Linux systems, as a consequence the library itself must be programmed very efficiently. Only the basic system library (g)libc-library2 has to be used. According to Mitchell et al. (2001) the ld-linux-library is also necessary if the system has to deal with libraries dynamically (loading during the system runs). interim report 5 Technical Approach 5.1 The Ping Measurement To explore the feasibility of using the Internet for remote control of robots the ping measurement was conducted. Over one week the round trip time (RTT) to the destinations was measured every minute. The gathered data was analysed statistically. A second ping measurement was conducted to proof the assumption that an overload of the local network causes the majority of the time delay. 5.1.1 Ping Ping is a tool which sends ICMP3 echo requests to the destination. The desti- nation computer echos the request package (sends it back to the sender). The initiator of the ping request measures the time between sending the ping and receiving its echo. This is the RTT, the time which is necessary to transfer data to the destination and back. The additional processing time on the destination is immanent. This value can be neglected because it is very short in comparison to the transfer time. The fault caused by neglecting this time minimises when the whole ping time increases. By default a ping package has an overall size of 84 bytes and contains the fol- lowing parts: the IP header (20 Bytes) which specifies the source and target (IP) address and some network management information. The ICMP header (8 Bytes) contains a sequence-number, a checksum, and an identifier. The last part is the 2 This library contains the commands for the C programming language 3 The Internet Control Message Protocol works at the same level as the UDP and TCP ­ it uses the Network Layer, the Internet Protocol (IP). It is used for troubleshooting and to announce network errors and timeouts. Please refer to RFC 792 (Postel, 1981) for details. A. Hofmeier, Final Year Project: Final Report 13 data part (56 Bytes) which contains a timestamp and filling-bytes. (Forouzan, 2001; Kozierok, 2004; Berkeley, 1996) Over one week 10080 pings were sent which correspond to 846720 Bytes or 826 kByte in one direction per destination. The same amount of data was sent back. 5.1.2 Source ­ Destinations The pings were sent from my private server which is located in the 'Schulzentrum Utbremen' a school in Bremen, Germany. It is connected through the local school network and the network of the University of Bremen to the Internet. This server was used because the network of the LSBU does not allow to send pings to external computers. All distances were calculated by using Global Positioning System (GPS) coordi- nates. The short overview about GPS coordinates given by Guthrie (2004) was used. All GPS coordinates were obtained from Maptech (2005) except the Unisa one which was adapted from Kennington (2000). It was not possible to obtain any exact GPS coordinates from the servers which were utilised. Coordinates from the home city or near objects were used. For this reason, the accuracy lays far beyond the GPS accuracy. In addition to this, the calculation results are air-line distances and not the real lengths of the cable of the transmissions. To calculate the distance the following steps needed to be performed. Calcula- tion of the difference between the latitude of the destination and the latitude of Bremen and the difference between the longitudes. After this the Pythagorean Theorem was used to calculate the distance (the hypotenuse). The following formula was used: distance = ( latitude1 - latitude2)2 + (longitude1 - longitude2)2 The destinations were selected to give a wide spectrum of distances. It was assumed, that the servers of the destination organisations were located within the organisation's main building or near to it. It was not possible to locate a LSBU server which echoes pings. For this reason, the LSBU did not become a destination. For details about the results and analyse of the ping measurement please refer to the section 6.1 (page 28). A. Hofmeier, Final Year Project: Final Report 14 Servername Name of Organisation Distance www.unisa.edu.au University of South Australia 17,000 km www.harvard.edu Harvard University (USA) 8,800 km www.nationalgallery.org.uk National Gallery of United Kingdom 1,000 km www.tu-dresden.de University of Dresden (Germany) 460 km mail.hs-bremen.de Mailserver of the University of 10 km Applied Science Bremen (Germany) Table 1: Destinations which were used in the Ping Measurement. 5.2 Basic Concept The first thing which was developed during this project was the basic concept. The network library provides the communication tools to the robot and to the server control program. A user-command takes the following way: A user enters a command into the user interface of the GUI/server. The server control program reads a command from the user through the user interface, evalu- ates it, and sends it through the IP network (the Internet) by using the functions of the network library. The network library on the robot's side receives the command and hands it over to the robot control program. The robot control program executes the command and controls the robot. The feedback from the robot follows this way in the other direction. It is difficult to clearly distinguish between these levels. For example: there is no boarder between the GUI and the server control program in this project. In addition to this the robot's side includes an user interface. (In the real world at least an emergency stop key has to be implemented on this side.) Within this project a GUI is implemented to simulate the assumed position of the robot. The name of this program is guirobot. The name of the Server Control Program (and its GUI) is guiserver. IP-Network Internet Hardware Control Program Network Library User Interface Control Program Network Library Robot Server Figure 5: Basic Concept which is assumed in this Project This communication has to be bidirectional. It must be possible to request data from the robot. This could be the acknowledgement for a command, obtaining A. Hofmeier, Final Year Project: Final Report 15 data of the robots environment, and to monitor the robot. 5.3 Implementation of the Library 5.3.1 Network Layers After the basic concept was clarified, the network library was implemented. The picture 5 does not show the entire truth. The network library by itself cannot transfer data through a network. It has to use lower levels. During this project it was decided to used TCP for the data transmission. (Please refer section 4.5.1 on page 7.) The TCP and the levels underneath had to be implemented as well. This is not part of this project. Fortunately this was done before and it is now possible to use the implementation in the Linux-Network- Stack. In addition to the network implementation in Linux there must be some hardware in form of a Network Interface Card (NIC) and some network facilities like cables and hubs. Figure 6 gives an overview about the network layers which were used in this project. Transport Layer Network Layer Data Link Layer Physical Layer TCP IP MAC/Ethernet Hardware Network Int. Card GNU Linux Network Stack includes Drivers Application Layer Application, Server and Robot Control Program Network Library OSI-Model Internet Implemented by Figure 6: Overview of the used Network Layers 5.3.2 Usage of the Linux Network Implementation The Linux kernel provides an interface in form of system calls to allow (user mode) programs to use its facilities. This section gives an overview about these A. Hofmeier, Final Year Project: Final Report 16 system calls and the way in which they were used in this project. For more detailed information please refer to IBM (1995). Figure 7 shows on outline of the steps which are necessary to establish, to use, and to disconnect a communication link ­ a TCP socket stream. Create an endpoint for socket() a connection (a Socket) Connect this endpoint bind() with a local port Start listening for listen() connections on this port Accept a connection, get a accept() new discriptor to this new connection Transmitt data send() Receive data recv() Disconnect close() gethostbyname() resolve the name of the destination to an IP (network) address. socket() Create an endpoint for a connection (a Socket) connect() Connect this endpoint to the given destination. recv() Receive data send() Transmitt data close() Disconnect TCP Stream a b a b a must be done before b a sents data to b Establish/ConnectDisconnectOpen/Usage Server Client (allows connection) (connects) Sockets Figure 7: Life Cycle of a TCP Socket Stream It is possible to accept() more than one connection on a bound port. For this reason it is necessary to distinguish between the socket which is bound to the port and those for incoming connections. For each new connection a new socket is generated and given back by this system call. The communication (in Open / Usage) between both sides is duplex (bidirec- tional). The duplex mode (pseudo-, half-, or full-duplex) depends on the under- lying network equipment. There is no prescribed order in which the sides have to call send() and recv(). The functions accept(), recv(), and send() will block4 by default if there is no connection to accept, no data to receive (no data was sent), or the sent-buffer is full (cannot absorb more data). This behaviour can be changed with fcntl(). 4 If a system call cannot complete its task because not all necessary data is received it waits until it can be completed. This causes a suspending of the calling function. This is called the function is "blocked". A. Hofmeier, Final Year Project: Final Report 17 For a detailed description of the system calls used please refer to the manual pages within the 'Linux Programmer's Manual'. To simplify the process of establishing a socket-stream connection the following functions were implemented: · socket_accept(): Start a new thread, wait for connections, and call a function when someone connects. · socket_bind(): Bind a socket to a port (Server side). · socket_connect(): Connect a TCP-stream to a server (Client side). In addition to this it was necessary to implement several sub-functions. All these functions can be found in the file src/lib/libcomm.c (appendices, section 10.3.2 on page 65). For a detailed description with parameters and return values of the listed func- tions please refer to the Application Programmer Interface (API) of the network library ­ libcomm ­ in the appendices section 10.2 (page 49). Please reefer to section 6.3.1 (page 32) for details about the tests which were conducted to proof the correct behaviour of this functions. 5.3.3 Block Transfer Functions Any data which is sent to a socket that is connected to a TCP stream will be transfered to the socket on the other side of this stream. The lower levels take care about the integrity of the data. The TCP monitors and corrects the order of the data and its integrity. This is important because data packages may follow different routes through the network or packages are lost and must be retransmitted. In both cases the packages need to be re-sorted on the receiver's side. If the connection is broken due to a network fault, recv() and send() will return an error. For control purposes often blocks need to be transfered. A block in this context is a unit of data. For example: two integers for x and y target coordinates. If the size of the datablock is constant it is simple to receive or transmit: recv(fd, buf, n, MSG_WAITALL); A. Hofmeier, Final Year Project: Final Report 18 send(fd, (void *) buf, n, 0); In this example fd describes the used socket, buf is a pointer to the block, and n the number of bytes to send or receive. MSG_WAITALL tells the function to wait until all n bytes are received. A problem may occur at this point: TCP is a stream protocol and acts in this manner. It guarantees that the bytes are in the right order. But it does not guarantee that if m * n bytes were sent, it will be received as m * n bytes. If, for example, two blocks with 10 bytes each were transmitted it is possibly received in one block of 20 bytes, two blocks with 5 and 15 bytes, or three blocks ... This problem is caused by the transparency of the network stack. The higher levels do not know what the lower ones do. In addition to this TCP buffers incoming and outgoing data. Once the send() is called the behaviour of the network stack depends on many things. For example: buffer size, network load and speed. On the receiver's side all received data is stored in a buffer. recv() can load already received data from the buffer or it has to wait for some data to be received. This behaviour can be configured as mentioned earlier. If different size blocks are possible it can be tricky to distinguish between two blocks because there is no way to know what block-size was used. To bypass this problem the Block Functions were implemented. The Block Functions use a protocol to transferring blocks. This protocol trans- mits a block as follows: 1. 2 Bytes : Type: Type of the datablock can be chosen by the user of the function 2. 2 Bytes : Length: Length of the datablock. 3. n Bytes: Datablock ) These are two byte-values used as a 16 bit integer. For this reason these values can vary in the range between 0 and 65535. A consequence of this is that the maximal size of a datablock is 65535 bytes. In addition to this the integer must be organised in the same way on both sides (GUI/server and robot). This can be tested be the test-program src/tests/test002integer.c (appendices, section 10.7.2 on page 115). In the programming language C data blocks are handled as pointers to the first unit (in this case a byte). There is no possibility to know how many units need to A. Hofmeier, Final Year Project: Final Report 19 be processed if only the pointer is given. For this reason the block functions need to handle the size as well. Figure 8 gives a schematic of the basic block function. block_send() block_receive() TCP Stream Sockets Datablock Size Type Datablock Size Type Figure 8: Basic Concept of the Block Functions Implemented functions: · block_send(): Send a datablock. The function blocks until the whole block is transfered to the buffer. If the buffer is full, data has to be sent first before it can continue. · block_receive(): Receive a block. This function blocks until a whole block is received. · block_ifdata(): Tests if there is data in the receiving buffer. The result of this test is returned. · block_receive_poll(): Starts receiving a block if there is any data in the buffer. The function waits until the whole block is received. If there is no data in the buffer, an error-code is returned. · block_call(): Starts a thread (goes to background, the calling function can continue) and waits for a block to be received. When this event occurs a given function is called to process this received datablock. In addition to this several subfunctions were implemented. All these functions can be found in the file src/lib/libcomm.c (appendices, section 10.3.2 on page 65). For a detailed description with parameters and return values of the listed func- tions please refer to the API of the network library ­ libcomm ­ in the appendices section 10.2 (page 49). Please refer to section 6.3.2 (page 33) for details about the tests which were conducted to proof the correct behaviour of this functions. A. Hofmeier, Final Year Project: Final Report 20 5.3.4 Line Monitoring Functions In this project it was decided to implement a set of functions to observe the network link (line). As explained in section 4.5.5 (page 10) this functions should be able to recognise if the network link becomes too slow to be used for remote controlling. In this case a function which takes appropriate actions (stop the robot) must be called. The basic concept of these functions was adapted from ping. A data packet is sent to the other side which echoes it (sends it back to the original sender). The time between the "ping" launch and the arrival of its echo is measured. If this time exceeds a specific value a exception-function is called. This implementation uses a TCP socket stream (not ICMP which is used by the original "ping") to transmit one-byte messages. Because of the different layers which are in use (TCP, IP, and Ethernet) the size of the data package increases to 67 bytes (1 byte data, 32 byte TCP, 20 byte IP, and 14 byte Ethernet). It can be helpful to distinguish between two levels of real time exceptions (time- outs): 1. Soft Real Time Exception: If this time was exceeded no serious conse- quences can occur. It can be ignored but it is an indicator that something is going wrong, possibly a forewarn. If too many of these timeouts occur together they can become a hard real time exception. 2. Hard Real Time Exception: If this time limit is exceeded an uncorrectable error is assumed. An appropriate action is to shut the system down (in particular the robot) to a safe state. The following functions were implemented: · linemonitor() this function connects the given server on the given port and starts sending "pings". After one byte (used as a ping) was lunched, the function calls poll()5 to determine if the answer (echo) arrives within the soft-timeout. If this was not the case a specified exception function is called and poll() will be called again. It determines if the answer is received within hard-timeout (hard-timeout is used as an offset value based 5 This is a system call which suspends the current function until data is received or a given timeout is exceeded. Please refer to the 'Linux Programmer's Manual' for a detailed description. A. Hofmeier, Final Year Project: Final Report 21 on soft-timeout). If this answer was received in time the function waits a specified time before is sends the next ping. If this does not happen the exception function is called. In addition to this the exception-function is called if the connection breaks down, an emergency-stop-code was received, or an invalid answer (answer (echo) differs from request (ping)) was received. This function should run on the dangerous side (robot side) because the real-time-timeouts are more accurate than within the server function. · linemonitor_server() this function is the server counterpart to the earlier mentioned function. It opens a specified port, waits for a connection and echoes (sends back) all received data. This function is less accurate in recognising timeouts because the wait-time (time before the next ping is sent by the linemonitor()-function) has to be included. As mentioned this function should run on the less dangerous side because of this fact. This function does not send pings by itself, it only echoes the received data. After one ping is echoed the function calls poll() to determine if the next ping arrives within wait-time plus soft-timeout. If the time-limit was ex- ceeded it calls the exception function and repeats this procedure for the hard-timeout. The function repeats this until it is terminated. · linemonitor_emergencystop() sends an emergency-stop code which causes an exceptions within the linemonitor()-function. In addition to this, the function linemonitor_thread() as "background"-part of the linemonitor()-function was implemented. All these functions can be found in the file src/lib/libcomm.c (appendices, section 10.3.2 on page 65). Problems with the implementation It was planned to provide the accurate round trip time (RTT) which was taken by the "ping". The system call select() which waits for an event (for example incoming data) was used to realise this. This system call provides a possibility to request time which the calling function was suspended. This functionality can be used to determine a exact value for RTT but it do not work. The function is may be not compatible with sockets. There was no direct hint about this in its manual page. For this reason the system call poll() was used instead. This system call do not allows to determine the exact time, only if the timeout was exceeded or not. For a detailed description with parameters and return values of the listed func- tions please refer to the API of the network library ­ libcomm ­ in the appendices section 10.2 (page 49). A. Hofmeier, Final Year Project: Final Report 22 Please refer to section 6.3.3 (page 33) for details about the tests which were conducted to proof the correct behaviour of this functions. 5.3.5 Authentication? 5.4 Demonstration with a Real Robot One objective of this project was to demonstrate the function of the library on a real robot. 5.4.1 The Robot It was decided to use a robot with two degrees of freedom. The robot itself is attached to a certain place but can move a platform in horizontal (x) and vertical (y) direction. The Robot is driven by a pneumatic system which is controlled through electronic valves. There are four valves, one for each direction in both dimensions. To move the platform in a direction the assigned valve has to be opened. A valve opens at an operation voltage of 24V. The figure 9 gives a basic overview about the structure of the robot. Unfortunately there was no interface, neither hardware nor software to control the robot with a Linux machine. Both was implemented in this project. 5.4.2 Hardware-Interface to the Robot It was decided to use the parallel port to control the robot because only four actors needed to be switched on or off. A feedback from the robot was not intended. As mentioned earlier the valves to control the robot are driven by 24V. The valves consuming about 100mA. This value was measured under operation with 24V. The parallel port is neither able to deliver 100mA nor 24V. It works with 5V and can provide a few milliamperes. To connect the valves to the parallel port an amplifier is required. Figure 10 shows the amplifier circuit which was designed to control the valves by using the parallel port. If the output of the parallel port is low (0 = 0V), UR is zero either. If UR is zero, no current flows into the basis of the transistor. A. Hofmeier, Final Year Project: Final Report 23 Movable Platform Valves for Vertical Movement Valves for Horizontal Movement Slide (active: up/down passive: right/left) Carriage (right/left) Track for Carriage Base Frame Figure 9: Basic Structure of the Robot The transistor is closed, UCE 24V and UV lave 0V . The valve is closed. If the output is high (1 = 5V), UR 4.3V , UBE 0.7V . The transistor is open: UCE 0V and UV lave 24V . The valve is open. (Please refer to the following calculations.) Calculation of the substitution resistor for the values. Used in the simulation. This value is only an approximation because of the inaccuracy cased by the power supply which generates UL and the measurement of IL. RL = UL IL = 24V 100mA = 240 Calculation of R. Assumption: parallel port is operating (Hight = 1) and gener- ates U0 = 5V ; 1mA is sufficient to open the transistor entirely. R = U0-UBC 1mA = 4.3V 1mA = 4300 The calculated resistor value is not available (in E1 series). For this reason it was decided to use 4700. The reverse Calculation: IR = Iparallel-port = U0-UBC R = 4.3V 4700 = 0.91mA This value is acceptable. A. Hofmeier, Final Year Project: Final Report 24 Valve +24V Parallel Port Bit x GND UR R T BC337-16 D 1N4007 RL U0 UBE UL UCE 4700 Figure 10: Circuit of the Hardware-Interface Worst case calculation: if the transistor generates a short-circuit between C and B, 24V on B. (Parallel port delivers zero, 0V.) IR = Iparallel-port = - 24V 4700V = -5.11mA The parallel port should not be damaged by this current if this happens. The diode (D) is used to protect the transistor in case of a high self induction voltage. The magnetic field in an inductive element depends on the current through it and vice versa. If an inductive load is switched off, the magnetic field (which do not disappears in infinite short time) forces a current. If the transistor is closed, the current cannot flow and charges are divided. A hight voltage is generated, which can destroy the transistor. The diode allow the current to flow, no charges are divided, no problem occurs. The inducted current flows in the opposite direction as the operation current. The diode has to allow the current only in this direction. Because of this the transistor is not bypassed during normal operation. The shown circuit was built four times, one time for each valve. The main challenge in this part of the project was to built this four amplifiers small enough to fix them info the parallel port plug. Table 2 explains in which way the interface to the robot is wired. A. Hofmeier, Final Year Project: Final Report 25 PIN Bit Operation 2 0 Move Up 3 1 Move Down 4 2 Move Right 5 3 Move Left 18 - GNDa Table 2: Connection between the Parallel Port and the Robot's Actors. · a ) GND is a abbreviation for Ground which describes the common 0V-level. Please refer to section 6.4.1 (page 34) for details about the tests which were conducted to proof the correct behaviour of this functions. 5.4.3 Software-Interface to the Robot A peace of software ­ the software part of the interface ­ was implemented to control the robot by using the hardware-interface. According Messmer and Dembowski (2003) the basis IO-port of the parallel port is by default located on the IO-address 0x378. The eight output bits can be directly controlled through this address. The following eight addresses can be used to control other features of the parallel port. Normally this IO-ports are only accessed by kernel drivers. This drivers providing an interface (for example, some special files in /dev) to user level programs. User programs access the hardware only through the kernel. The reasons for this are security aspects. If any program could access the hardware directly, it could bypass the access permission management of the system. For example: copying private files by accessing the harddrive directly. To be able to access IO-ports under Linux directly the program has to have the right to do this. This right is reserved for programs which run with root (system administrator) privileges. Those programs can enable the access to the IO-ports by calling the system-call iopl(3). After this system call was successful, the IO-ports can be accessed by using inb() and outb(). inb(p) reads one byte from port p and returns it. outb(v, p) writes one byte which has the value v to the port p. (Linux Programmer's Manual) To prevent collisions between the software interface and conventional Linux drivers these drivers has to be unloaded: A. Hofmeier, Final Year Project: Final Report 26 · parport_pc: low level driver for the parallel port of a PC · parport: general driver for parallel ports · lp: driver for Line Printers The software interface calculates the x and the y on the basis of given target coordinates and stored coordinates. The interface has to remember the last coor- dinates of the robot's platform because there is no feedback from the robot. There is no possibility for the interface to request the current position of the platform. When the interface is initialised it moves the platform to y = 0. The x value is ignored during this initialisation process because the robot can be damaged if the interface drives the horizontal axes until the whole distance was covered and x = 0. If x was not 100% the platform would hit its limit. The interface assumes linear behaviour of the robot. This means that 50% of the time which is necessary to cover the whole distance is necessary to cover exactly 50% of the distance (independent from start-point and direction). Unfortunately the robot is not accurate enough. For this reason the process of moving the robot's platform to some target coordinate will produce a great discrepancy between the stored and the real coordinates. This discrepancy increases with every movement because of the assumption that the stored coordinates (result of the previous movement) were correct. The following functions were implemented: · interface_init() to initialise the interface · interface_driveto() drives the robot to given absolute coordinates. · interface_stop() shuts the interface down. Several subfunctions needed to be implemented to realize this functionality. This functions can be found in the file src/example/interface.c (appendices, section 10.5.1 on page 92). Please refer to section 6.4.2 (page 35) for details about the tests which were conducted to proof the correct behaviour of this functions. A. Hofmeier, Final Year Project: Final Report 27 5.4.4 GUI and Simulator Some kind of user interface is necessary to control the robot. It was decided to use GTK-2.0 to implement a Graphical User Interface (GUI) for this purposes. GTK is the GIMP Toolkit, a set of tools and libraries to implement GUIs. GIMP is the free GNU Image Manipulating Program. Both, GIMP and GTK are under LGPL6 . (Blandford et al, 2004) After a basic understanding of the function of GTK was gained a illustration of the robot was implemented. This illustration is used as an input to control the robot and as a simulation. This was realized as two GUIs: one on the server side (guiserver) which allows to manipulate the position of the robot's platform by clicking on in and moving it. The other on the client/robot side (guirobot) which shows (simulates) the current (assumed) position of the platform. There is no possibility to influence the position of the platform on this side. The GUIs are using the functions of the network library to transfer the commands (destination position) over a network from the server to the robot. In addition to this the linemonitor is used to observe the quality of the network connection. An emergency stop can be applied over the linemonitor. If an emergency stop code is transmitted or the connection performance falls bellow a certain level (hard timeout occurs) the interface of the robot is shut down ­ the robot stops all movements immediately. These function can be found in the following files: · src/example/guicommon.c (appendices, section 10.6.1 on page 97) draws the sketch of the robot and calculates the new coordinates which were given by mouse-inputs (click and movements). · src/example/guirobot.c (appendices, section 10.6.2 on page 100): imple- mentation of the robot control program and the simulator. This implemen- tation uses the interface to the robot. · src/example/guiserver.c (appendices, section 10.6.3 on page 106): im- plementation of the remote control program. It reads commands from the user and transmits them over the network to the guirobot. Please refer to the section 10.1 (page 46) for a more detailed description of the implemented GUIs. 6 GNU Lesser General Public License, please refer Free Software Foundation (1999) A. Hofmeier, Final Year Project: Final Report 28 The main challenge during the implementation of the GUIs was the re-drawing of the simulation. An (from GTK) independent thread receives the new position from the server and calls the function which plots the sketch of the robot. Be- cause of this GTK do not recognises that something was changed. The result of this was that the changes were not applied to the screen. It was difficult to find a appropriate solution to this problem. Many redraw-function do not work and the others were causing a 'Xlib: unexpected async reply' ­ a crash of the program. This happens because the GTK-thread and the independent thread were not syn- chronised. This synchronisation is now restored by calling gdk_thread_enter() before drawing the sketch of the robot than gdk_window_process_all_update() to force a redraw of all components. After this gdk_thread_leave() unlocks the main thread. To use this functions the gdk-library (extension of GTK for platform independence) needs to be loaded and initialised. Please refer to section section 6.5 (page 35) for details about the tests which were conducted to proof the correct behaviour of this functions. 6 Results and Discussion 6.1 Analyse of the Ping Measurement The ping measure was conducted twice: 1. from Mon, 01. November 2004 00:00 to Sun, 07. November 2004 23:59 ­ normal school week. 2. from Mon, 26. December 2004 00:00 to Sun, 01. January 2005 23:59 ­ holiday period. The table 3 gives an overview about the average of the results. It faces the distance to the destination which the minimal (Min), average (Avg) and maximal (Max) values for each destination and conducted measurement (Try). In Addition to this the number of lost pings (Lost [n]) and the percentage related to the total number of pings (Lost [%]) is given for each destination and measurement. The data was pictured in a diagram (on page 31) to gain a better understanding. The one week (real-time) during the measurement was conducted is plotted on the x-axis with a main interval of one day. The unit of the y-axis is milliseconds. A. Hofmeier, Final Year Project: Final Report 29 Servername Distance Try Min Avg Max Lost Lost Organisation [km] [ms] [ms] [ms] [n] [%] www.unisa.edu.au 17,000 1st 358 431 9326 1432 14.21 Uni South Australia 2nd 350 370 712 40 0.40 www.harvard.edu 8,800 1st 120 158 1754 16 0.16 Harvard University (USA) 2nd 121 137 470 2 0.02 www.nationalgallery.org.uk 1,000 1st 47 83 1673 15 0.15 National Gallery of UK 2nd 48 64 401 3 0.03 www.tu-dresden.de 460 1st 21 59 1571 2 0.02 Uni Dresden (Germany) 2nd 21 36 374 2 0.02 mail.hs-bremen.de Uni 10 1st 6 39 1632 145 1.44 A.S. Bremen (Germany) 2nd 6 11 204 61 0.61 Table 3: Overview of the Results of the Ping Measurement. This axis represents the time which was taken by the ping (RTT) to travel to the destination and back. The graphs were shifted on the y-axis to be able to show all destinations in one diagram. The order of the graphs is equal to the order of the above listed destinations. The upper graphs where shifted to 6000 , 4000 , 2000 and 1000. ) These graphs were shifted to a grid line. This first expected result of this measurement was that the time delay depends on the covered distance. This can be seen in the average values (table on page 29) as well as in the first diagram on page 31. The minimal, average and maximal values on each measurement increasing with the distance. The graphs in the diagram represent this by shifted higher with the distance. The second observation was, that the time delay for all destinations increases to very high values from around 8am to around noon and decreases from noon to 7pm to "normal" values. All graphs following almost the same pattern. It was assumed, that there is a change in the time delay depending on the daytime. However, the increases should have been shifted by the time difference to the time zone of the destination if the destination causes a countable amount of the time delay. All curves have almost the same shape. Because of this it was assumed that the same reason causes the time delay for all destinations. If this is translated into network-language, it means that all pings went through the same sub-network. There is only one sub-network which fulfil this requirement: the local school and university sub-network through which my server is connected to the Internet. After this network, the pings went different ways. A. Hofmeier, Final Year Project: Final Report 30 To proof this assumption, that the workload of local school and university network was causing the majority of the time delay, a second measurement was conducted. To exclude the possibility of high work load, this measurement was conducted during the holiday period. In comparison to the first measurement, the time delay is almost stable. Except some peaks on Monday which may be caused by network maintenance. 6.2 Result of the Ping Measurement As a conclusion of the ping measurement it can be said, that the Internet can be used for remote control quite well if some assumptions are made: 1. The network link and the caused time delay must be explored before some statements about its usability can be made. The levels of time delay are changing from network link to network link and often even from hour to hour. This has to be well considered. After this analysis the time delay becomes well known. However, there is still a big random component, because of the unpredictability of behaviour of the unknown part of the network link. The most of the network link is unknown. 2. There must be a possibility to observe the network link quality. Appropriate actions must be taken if the network link becomes unusable for remote control purposes. This is essential for safety reasons. 3. The bandwidth to the Internet must be wide enough to carry the workload without causing unacceptable time delays. The definition of unacceptable depends on the real time requirements of the remote control system. It is not a good idea to share the network-access with other parties because this parties may causing unpredictable workloads and time delays. 4. If the bandwidth is shared with some other parties, it may helps to imple- ment some priority system. A. Hofmeier, Final Year Project: Final Report 31 0 2000 4000 6000 8000 10000 11/01 00:00 11/02 00:00 11/03 11/04 11/05 11/06 11/07 00:00 11/08 00:00 RoundTripTime(RTT)ofpingpacketinms Date and time when the ping was sent University of South Australia -- www.unisa.edu.au (RTT + 6000) Harvard University, Cambridge/USA -- www.harvard.edu (RTT + 4000) National Gallery London/UK -- www.nationalgallery.org.uk (RTT + 2000) Technical University Dresden/Germany -- www.tu-dresden.de (RTT + 1000) University of Applied Science Bremen/Germany -- mail.hs-bremen.de 0 2000 4000 6000 8000 10000 12/26/04 00:00 12/27/04 00:00 12/28/04 12/29/04 12/30/04 12/31/04 01/01/05 00:00 01/02/05 00:00 RoundTripTime(RTT)ofPingPacketinms Date and time when the ping was sent University of South Australia -- www.unisa.edu.au (RTT + 6000) Harvard University, Cambridge/USA -- www.harvard.edu (RTT + 4000) National Gallery London/UK -- www.nationalgallery.org.uk (RTT + 2000) Technical University Dresden/Germany -- www.tu-dresden.de (RTT + 1000) University of Applied Science Bremen/Germany -- mail.hs-bremen.de Figure 11: Results of the Ping Measurements. Top: First Measurement, Normal School Week. Bottom: Second Measurement during Holiday period. A. Hofmeier, Final Year Project: Final Report 32 6.3 Test of the Library 6.3.1 Basic Functions To test the basic function (socket_bind() and socket_connect()) the test- program src/tests/test001sockets.c (appendices, section 10.7.1 on page 112) was implemented. The function socket_accept() was tested by the program sr- c/tests/test003block.c (appendices, section 10.7.3 on page 116), please refer to section 6.3.2 (page 33). This program implements server and client to test the network-functions on the loop-back-network7 of the local machine. Server binds a port, receives one 8192- byte-block, inverts it and send it back. Client side connects to the server, send a random-block, invert it, receive a block, and compares both. If the both blocks (received and local inverted one) are equal it is assumed that the test was suc- cessful. Destination Test Result 127.0.0.1a connect to IP OK localhostb resolution of a local namec OK lblackyd resolution of a local namec OK hofmeira.student.sbu.ac.uke Resolution by DNSf OK Table 4: The Tests-Results of the Basic (Socket) Function of the Network Library ) This tests will only work, if the name of the local machine is equal to the mentioned name. a ) This IP-address should exist on every computer and is in any case. It is the loop-back-network to the local machine. b ) This name should exist on every computer and is in any case an alias of the local machine. c ) Uses /etc/hosts a host-IP-table to resolve the name of a computer to its IP. d ) Name of the local computer (on which the test were executed). e ) Name which is allocated to the local computer by a DNSf . f ) DNS stand for Domain Name Server. This is a system to manage unique global names. 7 This network is in use if a computer establish a connection to itself. A. Hofmeier, Final Year Project: Final Report 33 6.3.2 Block Transfer Functions The test-program src/tests/test003block.c (appendices, section 10.7.3 on page 116) for the block transfer functions work in almost the same way as the test-program for the basic socket functions. Changes are: the program connects localhost and uses the block transfer functions to transfer blocks. The server-side program uses and tests this functions (in the following order) 1. block_receive(), 2. block_receive_poll(), 3. block_receive_call(), and 4. socket_accept() (which calls block_receive_call()) to receive a block. block_receive_send() is used to send this block back. The client side only uses block_receive_send() and block_receive_receive(). After this four tests are done, the authentication (functions socket_md5auth()) is tested as well. This is done by running one test and authenticate the connection before the block-transfer starts. After some troubleshooting all functions work properly. During the test 3 and 4 the error "recv(): Bad file descriptor" occurs because the thread still tries to receive after the client closes the connection. The thread will recognise (through this exception) if the connection is closed and terminate. This event is docu- mented by the message "(server: connection terminated.)", which were perceived during the test. 6.3.3 Line Monitoring Functions A small test-program src/tests/tes005realtime.c (appendices, section 10.7.6 on page 125), which only implements the linemonitor-functions was used to test these functions. This program starts either the server or the client of the linemonitor-system depending on the parameters which were given: · Client Mode: run_tes005realtime server port soft_msec hard_msec wait_msec A. Hofmeier, Final Year Project: Final Report 34 · Server Mode: run_tes005realtime port soft_msec hard_msec wait_msec The client needs to know which server on which port has to be connected, while the client only needs to know, which port to bind (and wait for incoming connections). Please refer to section 10.1.4 (page 48) for a description of the remain parameters. 6.4 Test of the Interface to the Robot 6.4.1 Hardware-Interface Before the hardware-interface was implemented, the circuit was tested with MultiSIMTM 2001. The result of the simulation validates the results of the calculations in sec- tion 5.4.2 (page 22). This simulation uses a substitution resistor (calculated as RL) to simulate the valve. Table 5 gives an overview about the measurements which were conducted to test if the hardware was implemented properly. Test Result Connection from +24V to the valves OK (low-resistance) Connection from +24V to other components (Valves not connected) OK (none) Connections among the GNDs OK (low-resistance) Connection between parallel output bits and GND (both direction because of the diode in the transistor) OK (high-resistance) Connection between parallel output bits and the input of the valves (C of transistor), both directions OK (high-resistance) Connection among parallel output bits OK (none) Connection among valve inputs (Cs) OK (none) Table 5: Results of the First Test of the Hardware-Interface. After this test was completed, the valves were connected and the hardware was tested by setting the bits on the parallel port manually. In this test the robot was not moved, the pneumatic supply was off-line. It was tested if the valves switching on when a bit was set. The valves indicate this by a red light and by switching-noise. The result of this tests was, that the interface work properly. All valves can be controlled. A. Hofmeier, Final Year Project: Final Report 35 6.4.2 Software-Interface The software-interface was tested by monitoring the bits of the parallel port. At this time hardware-interface was not connected. After some troubleshooting the interface seemed to work properly. To be able to run the final test on the entire interface a test-program (src/ example/test001interface.c) (appendices, section ?? on page ??) was written. This program initialises the interface (interface_init()) first. After this it reads (x,y) coordinates from the keyboard and hand them over to the interface (interface_driveto()). After some mistakes were eliminated, the interface works properly. The major mistakes were a misinterpretation of the parameter of usleep()8 . Mil- liseconds instead of microsecond were used. As mentioned earlier, the movements of the robot's platform are not linear. For this reason the interface is not able to work accurate. 6.5 Test of the GUI and the Simulator The implementation and the testing of the GUI were running almost at the same time. All new included details were checked when there were ready. This test were conducted by myself because there is no point in writing a test-program to test the interface to the user. The user has to decide if the interface works properly or not. The GUI was implemented and tested in these steps: 1. Open a (program) window and draw the sketch of the robot in it. 2. Read the commands from the user. The new position of the robot's platform can be entered by moving (with the mouse) the sketch of it on the screen. 3. Transmit this new coordinates over a network to the other side and apply them to the simulated sketch. 4. Apply the new coordinate to the robot by using the interface. All these steps are fully implemented now. The system works. 8 System-call which suspends the calling function for a given time (unit: microseconds). A. Hofmeier, Final Year Project: Final Report 36 7 Conclusions and Recommendations for Fur- ther Work 7.1 Project Conclusions · During this project the possibility of using the Internet for remote control- ling of a robot was explored. This was done by conducting an analyse of an example connection through the Internet. This unearth that in this case the majority of the time delay (the most important restriction) were caused by the local network and not by the Internet. · This project implements a network library which make it possible to control a robot over the Internet. This library was demonstrated on a real robot by implementing an example system. It includes a server side which reads commands from the user and transmits them through the Internet to the robot's side. This side receives the commands, apply them to the robot, and simulates the behaviour of the robot. 7.2 Personal Conclusions · The three most challenging things for me during this project were to organ- ise my self (take responsibility), to document my work well (write logbook and reports), and to do this in English. I am sure that I made a lot of mistakes in this project but I see this as an important part of a learning process. In my opinion it is better to do the mistakes now ­ and learn from them ­ then to make them later in more important projects, for example, at work. Measured on the experience and knowledge I gained by doing this project it was a great success and very lucrative. · During this project I discovered, that is is a good idea to have an aim and a plan. If you do not have an aim, you can never achieve it, you will walk/work around in circles like homeless people. The point in having a plan is not to do all the work point for point as listed in the plan. No! The plan is much more a help to elaborate the direction. It helps to get an overview ­ thinks will not be forgotten so easily. · Today it is common to use the Internet to gain information. We expect that "there is something" but this "something" has to come from "somewhere" ­ A. Hofmeier, Final Year Project: Final Report 37 or better from "somebody". The most useful web pages are ­ in my opinion ­ the small and private ones. The most peoples expecting only something to be there ­ there are only a few people which providing something. Especially student producing much work during their studies. In most cases a lot of time was spent on producing. And what happens after the mark is given? Nothing. The work is often thrown away in the next drawer. In my opinion this is waste. For this reason I recommend to provide good final year projects and other work on the Internet. The reports are already in the computer. There is no big step to put them on the web. It is may considerable to add this as an objective to the final year projects. For example: All students have to produce a html-(or pdf)-version on CD from their documents, which can be provided online. I think it is important to contribute. If nobody contributes to the Internet, it will die. It will be only usable for commercial application. For this reason I try to present all my work on the Web. That gives me the feeling that my time and work was not wasted and can help someone. This project can be used as introduction and example in the following areas: 1. Communication through TCP sockets streams 2. Implementation of a Line Monitor 3. Implementation of a Block Transfer 4. Using of threads 5. Example implementation of a GUI on GTK with buttons, drawing areas and event handlers. 6. Examples in the C programming language, like general structures, function calls through pointers and some special things like converting integers to 16 bit numbers. 7. The results of the Ping Measurement can be helpful to understand the characteristics of Ethernet, IP-networks, and in particular the Internet. 8. Usage of Doxygen to create a documentation from the comments in the source code. For this reason, the entire project is available on the Web: ­ http://www.lgut.uni-bremen.de/an-h/en/papers/lsbu/fyp/ ­ http://www.an-h.de/en/papers/lsbu/fyp/ A. Hofmeier, Final Year Project: Final Report 38 7.3 Recommendations for Further Work · Porting to other platforms. All system calls which were used should be available within GDK (platform independent development library, exten- sion of GTK). For this reason it should be possible to use this library and make the network library platform independent. But this has to be well considered because of the performance. It is may no recommendable to use a platform independent implementation on the robot's side because of the overhead which is caused by this independency. If the robots uses an embedded system with Real-Time-Linux, there are may by not enough re- sources to use GDK. On the other side ­ the server side ­ this is completely different because of the performance of today's computer. · Implementation of other strategies to bypass the random time delay. This can help to make the library more useful for more applications. · Use this library in further projects. This library can help shortening the development of other projects which are aimed to control or transmit some- thing via the Internet. · Develop and implement a possibility to stop running linemonitor(), socket_accept(), or block_receive_call() treads. · As mentioned in section 7.2 (page 36) I think it is a good idea to provide good final reports and other work on the Internet. A. Hofmeier, Final Year Project: Final Report 39 8 Bibliography and References Addison, D. (2001) Embedded Linux applications: An overview [Online] Avail- able at http://www-106.ibm.com/developerworks/linux/library/l-embl.html (ac- cessed 20. October 2004) Andreu, D.; Fraisse, P.; Roqueta, V.; Zapata, R. (2003) Internet enhanced teleoperation toward a remote supervised delay regulator IEEE International Conference on Industrial Technology 10-12 December 2003 p663-668 volume 2 [Online] Available at http://0-ieeexplore.ieee.org.lispac.lsbu.ac.uk/iel5/9059/28746/01290733.pdf (ac- cessed 9. December 2004) Ball, P.; Farnham, J; Iraca, S. (1999) Transmission Control Protocol/Inter- net Protocol TCP/IP [Online] Available at http://cne.gmu.edu/itcore/internet/ tcpip/tcpip.html (accessed 11. December 2004) Belousov, I. (2004) Internet Robotics [Online] Available at http://www.keldysh.ru/pages/i-robotics/operidea.html (accessed 26. November 2004) Berkeley Distribution (1996) Ping Manual Page [Online] Available at http://snowhite.cis.uoguelph.ca/course info/27420/ping.html (accessed 12. Novem- ber 2004) British Standard (1992) Industrial robots ­ Part 6: Recommendations for safety; BS 7228-6:1992; EN 775:1992; ISO 10218:1992 [Online] Available at http://bsonline.techindex.co.uk/ (accessed 28. October 2004) Chen, Y.-M.; Chen, Y.-B. (2004) Research reform on real-time operating sys- tem based on Linux WCICA 2004. Fifth World Congress on Intelligent Control and Automation 5-19. June 2004 p3916-3920 Volume 5 [Online] Available at http://0-ieeexplore.ieee.org.lispac.lsbu.ac.uk/iel5/9294/29576/01342230.pdf (ac- cessed 20. October 2004) Elhaji, I.; Tan, J.; Xi, N.; Fung, W.K.; Liu, Y.H.; Kaga, T.; Hasegawa, Y.; Fukuda, T. (2000) Multi-site Internet-based cooperative control of robotic operations. Proceedings 2000 IEEE/RSJ International Conference on Intelligent Robots and Systems, 2, 31. Oct - 5. Nov 2000 p826-831 [Online] Available at http://0-ieeexplore.ieee.org.lispac.lsbu.ac.uk/iel5/7177/19309/00893121.pdf (ac- cessed 20. October 2004) A. Hofmeier, Final Year Project: Final Report 40 Feibel, W. (1990) Using ANSI C in Unix. Berkeley: Osborne McGraw-Hill Forouzan, B. A. (2001) Data Communication and Networking, 2nd edition. New York: McGraw-Hill. Guthrie, J (2004) Understanding GPS Coordinates [Online] Available at http://www.co.lincoln.wa.us/GIS(accessed 04. February 2005) Han, K.-H.; Kim, S.; Kim, Y.-J.; Lee, S.-E.; Kim, J.-H. (2001) Imple- mentation of Internet-based personal robot with Internet control architecture. Proceedings 2001 ICRA. IEEE International Conference on Robotics and Au- tomation 2001 p217-222 volume 1 [Online] Available at http://0-ieeexplore.ieee.org.lispac.lsbu.ac.uk/iel5/7423/20179/00932556.pdf (ac- cessed 20. October 2004) IBM Corporation (1995) TCP/IP Tutorial and Technical Overview: Ports and Sockets [Online] Available at http://www.auggy.mlnet.com/ibm/3376c210.html (accessed 22. December 2004) Kennington, A (2000) Alan Kennington's recommendations and suggestions [Online] Available at http://www.topology.org/reco/ (accessed 04. February 2005) Kernighan, B. W.; Ritchie, D. M. (1988) The C Programming Language, 2nd edition. London: Prentice Hall ISBN 0-131-10362-8 Kozierok, C. M. (2004) The TCP/IP Guide [Online] Available at http://www.tcpipguide.com/free/index.htm (accessed 12. November 2004) Liu, P. X.; Meng, M.Q.-H.; Gu, J.; Yang, S.X.; Hu, C. (2003) Control and data transmission for Internet robots Proceedings ICRA 2003. IEEE Interna- tional Conference on Robotics and Automation 14-19 September 2003 p1659-1664 volume 2 [Online] Available at http://0-ieeexplore.ieee.org.lispac.lsbu.ac.uk/iel5/8794/27834/01241832.pdf (ac- cessed 21. October 2004) Liu, Y.; Chen, C.; Meng, M. (2000) A study on the teleoperation of robot systems via WWW Canadian Conference on Electrical and Computer Engineer- ing 7-10. March 2000 p836-840 volume 2 [Online] Available at http://0-ieeexplore.ieee.org.lispac.lsbu.ac.uk/iel5/6844/18402/00849583.pdf (ac- cessed 20. October 2004) LRAV/AVDAY (1985) Computer in Control, 01: Introducing the Robot. [Video] A. Hofmeier, Final Year Project: Final Report 41 Maptech, Inc. (2005) Online Maps: Map Server [Online] Available at http://mapserver.maptech.com/ (accessed 04. February 2005) McKerrow, P. J. (1991) Introduction to Robotics. Singapore: Addison-Wesley. ISBN: 0-201-18240-8 Mitchell M.; Oldham J.; Samuel A. (2001) Advanced Linux Programming, New Riders Publishing [Online] Available at http://docs.linux.cz/programming/ other/ALP/advanced-linux-programming.pdf (accessed 20. December 2004) Plauger, P.J.; Brodie, J. (1989) Standard C - A Reference. London: Prentice Hall. ISBN 0-134-36411-2 Postel, J. (1981) RFC 792 ­ Internet Control Message Protocol [Online] Avail- able at http://www.freesoft.org/CIE/RFC/792/index.htm (accessed 11. Novem- ber 2004) Sato, H.; Yakoh, T. (2000) A real-time communication mechanism for RTLinux IECON 2000. 26th Annual Conference of the IEEE Industrial Electronics Soci- ety 22-28. October 2000 p2437-2442 volume 4 [Online] Available at http://0- ieeexplore.ieee.org.lispac.lsbu.ac.uk/iel5/7662/20956/00972379.pdf (accessed 19. October 2004) Schwarzenbach, J.; Gill, K.F. (1992) System Modelling and Control, 3rd edition. London: Edward Arnold. ISBN: 0-340-54379-5 Messmer, H.-P.; Dembowski, K (2003) PC-Hardwarebuch (German: PC- Hardwarebook) 7th edition. Munich: Addison-Wesley. ISBN 3-827-32014-3. Blandford, J; Clasen, M; Janik, T; Lillqvist, T; Quintero, F.M.; Ri- etveld, K; Sandmann, S; Taylor, O; Wilhelmi, S (2005) GTK+ ­ The GIMP Toolkit [Online] Available at http://www.gtk.org/ (accessed 28. March 2005) Free Software Foundation (1999) GNU Lesser General Public License. [On- line] Available at http://www.gnu.org/copyleft/lesser.html (accessed 28. March 2005) http://www.talula.demon.co.uk/allegro/ (accessed 28. November 2004) http://www.tcl.tk/software/tcltk/ (accessed 28. November 2004) http://www.geocities.com/SiliconValley/Monitor/3131/ne/osimodel.html (accessed A. Hofmeier, Final Year Project: Final Report 42 11. December 2004) http://www.erg.abdn.ac.uk/users/gorry/course/lan-pages/csma-cd.html (accessed 11. December 2004) http://www.stack.nl/ dimitri/doxygen/ (accessed 20. December 2004) MD5-Authentication ­ lecture (accessed 08. January 2005) http://mail.gnome.org/archives/gtk-app-devel-list/2004-October/msg00105.html (accessed 28. March 2005) http://www.soe.uogoelph.ca/webfiles/engg4420/lab2.html (accessed 28. March 2005) http://www.csa.iisc.ernet.in/old-website/Department Resources/Hypertext/gtk/gtk toc.html (accessed 28. March 2005) http://www.johnmalone.org/gtk/tutorial/sec-eventhandling.html (accessed 28. March 2005) http://www.gtk.org/tutorial/ch-advancedeventandsignals.html (accessed 28. March 2005) A. Hofmeier, Final Year Project: Final Report 43 9 Project Planning 9.1 Work Breakdown Final Year Project Communication Server <-> Robots Project Documentation Interim Report Presentation Final Report Theoretical Work Litarature Search Ping Measurement Basic Structure Demo with Real Robot Interface Robot <--> Library Programming Fix Together Feasibility Study Library (Server&Robot) GUI / Simulator Documentation (Source) Programming Documentation (API) Programming User's Manual DemonstrationTesting 9.2 Action Plan Estimated Duration Task in Weeks Precedence A Interim Report 3 - B Final Report 15 Feedback A C Clearing Project Aim/Objectives 5 - D Literature Search 8 - E Feasibility Study 3 C F Prepare Presentation 2 - G Interface to Robot 4 C H Design Structure 4 C I Build Library 8 (G) J Write Documentation (Library) 9 (I) K Build User Interface 7 (I) L Build Robot Simulator 7 (I) M Write Documentation (UI/Simulator) 5 (K),(L) N Interface between Robot and Library 3 G,(M) · Precedence: X: Task X has to be completed before the task can start. A. Hofmeier, Final Year Project: Final Report 44 (X): Task X has to be semi-completed before the task can start. That means that task X has to be in a state in which is possible to start a new task simultaneous. Tasks which run simultaneous can have an influence among each other. · Duration and Overlapping The weekly working time and effort is shared by overlapping tasks. For example the effort to write the final report will start at a lower level and increases during the project. On the other hand the effort on developing the library is decreasing. The main work will be done in the first three weeks. The last five weeks are planed for little changes to fit the library, the UI and the simulator together. · Holiday Periods The holiday periods are not included in the calculation. It is planned to do all project work within the lecture time. The holidays are scheduled as a reserve in case that the project-work takes longer than expected. 9.3 Milestones 1. On Tuesday, 9 November 2004, the project is defined by now and has been started. This is reflected by the interim report which is completed and handed in. 2. At this point (9th week of first semester) of the project it is possible to control the robot with a little experimental program. The interface to the robot is well understood. 3. In week 14 (first semester) an early simulation with library, user interface and simulator shows the basic function of the system. 4. At the end of week seven (second semester) the system works. It is now possible to control the robot over the Internet by using the library. This will be demonstrated. The simulation works as well. 5. On Tuesday, 26 April 2005, the project and final report are completed and handed in. A. Hofmeier, Final Year Project: Final Report 45 A. Hofmeier, Final Year Project: Final Report 46 9.4 Project Schedule ¡ ¢ £ ¤ ¥ ¦ ¢ § ¨ © § ¡ ¢ ¢ "! # $ % & ' ("! # $ % & ' ) 01 2 1 ( 3 4 5 6 7 8 9 @ ( A B C D 3 4 5 ( 3 4 5 6 7 E D 8 9 @ ( 3 F % C G HI PC % D Q G HI AQ D C % R S I T U VC W X 'T U C Y `C D & D U B P D C 'CQC a & b a S HD S % D C I % F % c DU I G I ' I d C R% & U & e &CQ b `C ' D a f C d IU & % D C I % g `C ' D a h e &CQ bi F % c DU e &CQ b G I ' I C &Q D I f C d IU & % D C I % gi F W C &Q D I h F % c DU ' # % G I ' I D % b `C ' D a p qr s 1 t u vs 1 ( 3 4 5 w s 0 xr q vs 1 S I T U V D % R % P I g P C @ 8y @ h F % C G HI g & @ 9y h P b ' DU $ I % F % C G HI g & 3 @y h d D c PC % D Q G HI g & @ 8y @ 3 h S % D C I % g f b 6y @ 3 D % b B & 7 y @ 3 h A I HQ C I % I c S DU C U D Q f I $ g P C @ 8y @ 4 h P b ' DU $ I % d D c PC % D Q G HI g & ( y @ 4 h PC % D Q G HI g & ( 6y @ 4 h C Y D S C I b A I HQ b #I $ SQ D % % b #I $ 10 Appendices A. Hofmeier, Final Year Project: Final Report 47 ­ Simulation only: If no access to the hardware is possible (the program does not run under root (with system administrator rights), access to the IO-ports is not possible. The program recognise this and shows (simulates) the robot movements on the screen only. ­ Simulation and Controlling: The IO-ports can be accessed, the inter- face is fully active. The program will show the new position of the robot on the screen and drive the robot to this position. · guiserver: This is the server or the remote control station. It allows the user to input the new position of the robot. This new position will be transmitted to the guirobot by using libcomm. The robot is shown (simulated) in both programs. The black rectangle pictures the platform of the robot which can change its position. The guirobot has to be started first. In the second step the guiserver connects to the guirobot. After this connection is established, the guirobot connects to the guiserver to monitor the stability and the speed of the line with the linemonitor(). Both programs are looking almost identical: Figure 12: Both Programs guirobot (left) and guiserver (right) directly After Startup. Their lookout (title line, buttons) depends on the used window manager and its configuration. In this case AfterStep is in use. The difference between this both Graphical User Interfaces (GUIs) is, that only the guiserver allows manipulations of the position of the robot's platform. The guirobot shows the actual position and drive the platform of the robot to the required position if the interface is active and can access the hardware. A. Hofmeier, Final Year Project: Final Report 48 10.1.2 Manipulate the Position of the Robot's Platform Click (with the left mouse-button) on the robot's platform (sketched as black rectangle) and move it with held mouse button to the new position. Release the button. An example of the result of this can be seen in the following screenshot: Figure 13: Both Programs guirobot (left) and guiserver (right) After a Move- ment of the Robot. 10.1.3 Stopping the Robot Both programs are able to stop all movings of the robot by clicking "Emergency Stop". This emergency stop is also executed if the window is closed or the program receives a terminate signal. In addition to this the linemonitor stops the robot if the the connection breaks down or if the server do not answers within a given time period. 10.1.4 Starting both Programs, Parameter As mentioned the guirobot has to be started first. This program receives the following parameters: guirobot port-to-bind soft_msec hard_msec wait_msec · port-to-bind describes the port on which guirobot has to listen for con- nections from the guiserver. The guirobot will connect to the home ad- dress of the guiserver and port-to-bind + 1 to establish a linemonitor connection. A. Hofmeier, Final Year Project: Final Report 49 · soft_msec tells the program how long it has to wait before a soft-timeout is assumed. A soft-timeout causes a message on the terminal. Specification in milliseconds. · hard_msec tells the program how long it has to wait after a soft-timeout is occurred, before a hard-timeout is assumed. A hard-timeout causes an emergency-stop of the robot. The hard-timeout is assumed if there is no response after soft_msec + hard_msec. Specification in milliseconds. · wait_msec specifies the time which has to be past after the last response was received before a new enquiry is sent. Specification milliseconds. The interface initialises the robot. That means driving the robot's platform to the (x=50,y=0) coordinates. The interface assumes that the robot is already in the position x=50. The x-position will not change. However this takes some time. The program is read if the window is displayed. After the window is displayed the guiserver should be started with the following parameters: guiserver robot-address port soft_msec hard_msec wait_msec · robot-address specifies the address of the computer on which the guirobot- program runs. This can be an IP-Address (Internet Protocol Address) or the name of the computer which must be resolvable by Domain Name Server (DNS). · port correlates to port-to-bind from guirobot and must be the same. · soft_msec correlates to soft_msec from guirobot and should be the same. · hrad_msec correlates to hard_msec from guirobot and should be the same. · wait_msec correlates to wait_msec from guirobot and should be the same. 10.2 API of the Network Library (libcomm) libcomm.c(3) libcomm.c(3) A. Hofmeier, Final Year Project: Final Report 50 NAME libcomm.c - Main part of libcomm. SYNOPSIS #include #include #include #include #include #include #include #include #include 'libcomm.h' #include 'md5.h' #include #include #include #include Functions void socket accept thread (struct LIBCOMMPTHREADP *libcommpthreadp) This is a part of socket accept() and must not called from the user. int socket accept (int sockport, int id, void(*socket accept do)(int fd, int id, char *pip, struct sockaddr in their addr)) Start a new thread, wait for connections and start socket accept do() when someone connects. int socket bind (int port, int cqueue) Bind a socket to a port (Server side). int socket connect (char *host, int port) Connect a TCP-stream to a server (Client side). char * block random (char *buf, int size) Get random numbers/bytes. void thread1 (struct LIBCOMMPTHREADS *libcommpthreads) This is a part of block call() and must not called from the user. int block call (int fd, int id, int term, void(*block call do)(int fd, int id, unsigned int type, char *buf, unsigned int size, int term), void(*block call term)(int fd, int id)) A. Hofmeier, Final Year Project: Final Report 51 Waits in a new thread for a datablock to be received and calls the function block call do() if this event occurs or block call term() when the connection terminates. int block ifdata (int fd) This function tests if new data is available to read on a stream. char * block receive poll (int fd, unsigned int *type, char *buf, unsigned int *size, unsigned int maxsize, int term) Test if is there data available on the socket's input buffer and starts receiving a block if there is. char * block receive (int fd, unsigned int *type, char *buf, unsigned int *size, unsigned int maxsize, int term) Receive a block (composition of: type, size of datablock and datablock) from a socket. int block receive integer (int fd, unsigned int *recvi) Receive an integer (two bytes; 16Bit) from the socket. int block receive nbytes (int fd, char *buf, int n) Receive n bytes from socket. int block send (int fd, unsigned int type, char *buf, unsigned int size) Send a block (composition of: type, size of datablock and datablock (buf)) to a socket. void free authinfo (struct AUTHINFO *destroy) Free the memory space which is used by an AUTHINFO structure. int socket md5auth (int fd, char *netname, char *name, struct AUTHINFO **plocallogin, struct AUTHINFO **premotelogin) Do both side authentification. AUTHINFO * getauthinfo (char *netname, char *name) Load authentication informations (netname, name, passwd, keyencrypt, keydecrypt) from authfile. void linemonitor server thread (struct LINEMONITOR THREAD DATA *linemonitor thread data) Thread used by linemonitor server() NOT for direct usage. int linemonitor server (int port, int soft msec, int hard msec, int wait msec, void(*linemonitor exception)(char *server, int port, int type)) A. Hofmeier, Final Year Project: Final Report 52 Monitor if the 'line' is fast enough: Server Application. void linemonitor emergencystop (int sock) Sends an 'Emergency Stop' to the client's side, linemonitor() will produce an 'Emergency Stop' exception (type 4). int linemonitor thread (struct LINEMONITOR THREAD DATA *linemonitor thread data) Thread used by linemonitor() NOT for direct usage. int linemonitor (char *server, int port, int soft msec, int hard msec, int wait msec, void(*linemonitor exception)(char *server, int port, int type)) Monitor if the 'line' is fast enough: Client/Robot Application. DETAILED DESCRIPTION Main part of libcomm. FUNCTION DOCUMENTATION int block call (int fd, int id, int term, void(* block call do)(int fd, int id, unsigned int type, char *buf, unsigned int size, int term), void(* block call term)(int fd, int id)) Waits in a new thread for a datablock to be received and calls the function block_call_do() if this event occurs or block_call_term() when the connection terminates. Parameters: fd (int) descriptor of socket id (int) arbitrary id of background process / thread term (int) 0: do not terminate the buffer, 1: terminate the buffer by appending a 0x00. block call do (int fd, int id, unsigned int type, char *buf, unsigned int size, int term) (function) this function is called if a datablock was received. fd, A. Hofmeier, Final Year Project: Final Report 53 id and term are the same as in block call(). type describes the type of the received datablock, buf is a pointer to this datablock and size is the number of bytes of the datablock block call term (int fd, int id) (function) this function is called if the connection terminates. fd and id are the same as in block call(). Returns: If all right zero otherwise non zero. int block ifdata (int fd) This function tests if new data is available to read on a stream. Parameters: fd (int) discriptor of stream to test Returns: (int) 1: Data to read; 0: No data to read char* block random (char * buf, int size) Get random numbers/bytes. This function read random numbers/bytes from /dev/urandom and stort this bytes in a buffer. Parameters: buf (char *) in which the bytes will be stored. If this parameter is equal to NULL dynamic memory will be allocated. size an integer, specifies ths size of the buffer (the number of the random bytes). WARNING: If buf is not equal to null, n*(size) bytes will be stored in this buffer without any check of ths size of this buf. Returns: (char *) a pointer to the buffer in which the random bytes are stored. A. Hofmeier, Final Year Project: Final Report 54 char* block receive (int fd, unsigned int * type, char * buf, unsigned int * size, unsigned int maxsize, int term) Receive a block (composition of: type, size of datablock and datablock) from a socket. Waits for a block to be received completely. WARNING: The integers (type and size; excluding fd) are only 16 bit values (0 - 65535). Parameters: fd (int) descriptor of socket type (unsigned int *) pointer to integer, this value can be used as buyer's option buf (char *) buffer for datablock. Memory will be allocated if this parameter is equal to null. size (unsigned int *) pointer to integer in which the size of the received datablock is saved. maxsize (unsigned int *) describes size of buf. This parameter will be ignored if bus is equal to null. term (int) 0: do not terminate the buffer, 1: terminate the buffer by appending a 0x00. Returns: (char *) pointer to buffer which contains the received datablock; NULL if fail. int block receive integer (int fd, unsigned int * recvi) Receive an integer (two bytes; 16Bit) from the socket. Parameters: fd (int) descriptor of socket recvi (unsigned int *) pointer to integer in which the received integer is saved. Returns: A. Hofmeier, Final Year Project: Final Report 55 (int) 2: OK; -1: fail int block receive nbytes (int fd, char * buf, int n) Receive n bytes from socket. Parameters: fd (integer) descriptor of socket buf (char *) buffer for saving the received bytes n (integer) number of bytes to receive Returns: (integer) n: OK; -1 fial char* block receive poll (int fd, unsigned int * type, char * buf, unsigned int * size, unsigned int maxsize, int term) Test if is there data available on the socket's input buffer and starts receiving a block if there is. WARNING: The integers (type and size; excluding fd) are only 16 bit values (0 - 65535). Parameters: fd (int) descriptor of socket type (unsigned int *) pointer to integer, this value can be used as buyer's option buf (char *) buffer for datablock. Memory will be allocated if this parameter is equal to null. size (unsigned int *) pointer to integer in which the size of the received datablock is saved. maxsize (unsigned int *) describes size of buf. This parameter will be ignored if bus is equal to null. term (int) 0: do not terminate the buffer, 1: terminate the buffer by appending a 0x00. Returns: A. Hofmeier, Final Year Project: Final Report 56 (char *) pointer to buffer which contains the received datablock; NULL if fail; 1 if no data available. int block send (int fd, unsigned int type, char * buf, unsigned int size) Send a block (composition of: type, size of datablock and datablock (buf)) to a socket. The function blocks until the whole block is transfered to the buffer. If the buffer is full, data has to be sent first. WARNING: The integers (type and size; excluding fd) are only 16 bit values (0 - 65535). Parameters: fd (int) descriptor of the socket to which buf should send type (unsigned int) This value can be used as buyer's option buf (char *) which should be send Returns: number of sent bytes, -1 if an error is occurt. void free authinfo (struct AUTHINFO * destroy) Free the memory space which is used by an AUTHINFO structure. Parameters: struct AUTHINFO *) pointer to structure to destroy. struct AUTHINFO* getauthinfo (char * netname, char * name) Load authentication informations (netname, name, passwd, keyencrypt, keydecrypt) from authfile. Parameters: netname (char *) specify the network name (may IP). NULL not specified. name (char *) specity the login name. NULL not A. Hofmeier, Final Year Project: Final Report 57 specified. Returns: (struct AUTHINFO *) the first entry from authfile which matches network name OR login name. If both values are NULL, the first entry of the authfile is given back. int linemonitor (char * server, int port, int soft msec, int hard msec, int wait msec, void(* linemonitor exception)(char *server, int port, int type)) Monitor if the 'line' is fast enough: Client/Robot Application. This function opens a socket stream, sents pings/bytes and wait for them to come back. The soft-timeout will called after soft_msec is timeouted. The hard-timeout will called after soft-timeout was called AND hard_msec is timeouted. wait_msec specifies the time which is waited after a ping is received befor the next one will be launched. Parameters: server (char *) server to be connected port (int) port to be connected soft msec (int) timeout in milliseconds which causes soft- real-time exception. hard msec (int) timeout in milliseconds which causes hard- real-time exception. wait msec (int) timeout for resent -- sending of the next ping. linemonitor exception (pointer to function) This function will be called if an exception occurs. It becomes the following parameters: server name (char *) which is always null, port (int): listend port and type (int) of exception which can be: 0: Connicion Fault, 1: Soft A. Hofmeier, Final Year Project: Final Report 58 Real Time Exception, 2: HARD Real Time Exception, 3: Transmission Fault, 4: Emergency Stop. void linemonitor emergencystop (int sock) Sends an 'Emergency Stop' to the client's side, linemonitor() will produce an 'Emergency Stop' exception (type 4). int linemonitor server (int port, int soft msec, int hard msec, int wait msec, void(* linemonitor exception)(char *server, int port, int type)) Monitor if the 'line' is fast enough: Server Application. This function opens a port and wait for the first connection on this port. All data/pings which is sent bei this first connection will be sent back. The soft-timeout will called after wait_msec AND soft_msec is timeouted. The hard-timeout will called after soft-timeout was called AND hard_msec is timeouted. Parameters: port (int) port which should be listend soft msec (int) timeout in milliseconds which causes soft- real-time exception. hard msec (int) timeout in milliseconds which causes hard- real-time exception. wait msec (int) timeout for resent -- sending of the next ping. linemonitor exception (pointer to function) This function will be called if an exception occurs. It becomes the following parameters: server name (char *) which is always null, port (int): listend port and type (int) of exception which can be: 0: Connicion Fault, 1: Soft Real Time Exception, 2: HARD Real Time Exception. A. Hofmeier, Final Year Project: Final Report 59 Returns: (int) Filediscriptor to the used socket. Only for usage with linemonitor emergencystop(). void linemonitor server thread (struct LINEMONITOR THREAD DATA * linemonitor thread data) Thread used by linemonitor server() NOT for direct usage. int linemonitor thread (struct LINEMONITOR THREAD DATA * linemonitor thread data) Thread used by linemonitor() NOT for direct usage. int socket accept (int sockport, int id, void(* socket accept do)(int fd, int id, char *pip, struct sockaddr in their addr)) Start a new thread, wait for connections and start socket_accept_do() when someone connects. Parameters: sockport (int) descriptor of a tcp socket/port from socket bind() id (int) arbitrary id of background process / thread. (May be it is a good idea to use the portnumber.) aocket accept do (int fd, int id, char *pip, struct sockaddr_in their_addr) (function) this function is called if somebody connects. fd is the descriptor of the new socket to the connected tcp-tream. id is the same as in socket accept(). pip contains the ip-address of the connected client. The structure their_addr contails all known information about the connected client. Returns: If all right zero otherwise non zero. void socket accept thread (struct LIBCOMMPTHREADP * A. Hofmeier, Final Year Project: Final Report 60 libcommpthreadp) This is a part of socket accept() and must not called from the user. This function is the thread which is started from socket accept() and runs in background. int socket bind (int port, int cqueue) Bind a socket to a port (Server side). This function creates an Socket and binds it to a local port. Parameters: port an integer which specifies the port cqueue an integer how many pending connections queue will hold in the waiting queue. Returns: The File Descriptor (FD) which allows access to the bound port. int socket connect (char * host, int port) Connect a TCP-stream to a server (Client side). Creates a socket and connect it over a TCP-stream to the specified port on the specified server. Parameters: host a string (char *) which specifies the name or the IP-address of the server. port an integer which specifies the port on the server. Returns: The File Descriptor (FD) which allows access to the TCP-stream-socket or -1 if the connection fails. int socket md5auth (int fd, char * netname, char * name, struct AUTHINFO ** plocallogin, struct AUTHINFO ** premotelogin) Do both side authentification. A. Hofmeier, Final Year Project: Final Report 61 This function is usually called just after a socket stream is established. The function must be called on both sides. Both sides following these steps: 1. get auth info ([login] name, passwd) by using getauthinfo() from name or netname for remote login 2. generate random numbers 3. exchange (first send, then receive) login names 4. exchange random numbers 5. calculate md5 checksum over the random numbers (received from other side) and the remote passwd. 6. exchange md5 checksums 7. get auth info from name (received from other side) for local login 8. calculate md5 checksum over the local random numbers and the local passwd. 9. check login -- compare the received md5sum (6.) with the generated one (8.); send acknowledgement 10. receive remote acknowledgement 11. return suitable values Parameters: fd (int) describes the socket on which the authentication has to be done netname (char *) use netname to resolve [login] name and passwd of the remote machine (NULL: not specified) netname (char *) use [login] name to resolve passwd of the remote machine (NULL: not specified; both NULL use first entry in file, see getauthinfo()) A. Hofmeier, Final Year Project: Final Report 62 plocallogin (struct AUTHINFO **) (pointer to pointer to an AUTHINFO struct) in this (double pointed) struct the local authinfo will be loaded, if the parameter is not null. premotelogin (struct AUTHINFO **) in this (double pointed) struct the remote authinfo will be loaded, if the parameter is not null. Returns: (int) 0: Authentication/Login OK; -1: remote login error; -2: login error on both sides; -3: local login error; -4: other (network) error; -5: cannot load remote auth info; -6: cannot load local auth info; void thread1 (struct LIBCOMMPTHREADS * libcommpthreads) This is a part of block call() and must not called from the user. This function is the thread which is started from block call() and runs in background. Parameters: libcommpthreads (struct LIBCOMMPTHREADS *) holds pointers to the functions to be call, fd (socket discriptor) and id. AUTHOR Generated automatically by Doxygen for Hofmeier_FYP:libcomm from the source code. Hofmeier_FYP:libcomm 11 Apr 2005 libcomm.c(3) A. Hofmeier, Final Year Project: Final Report 63 10.3 Source Code of the Network Library (libcomm) 10.3.1 src/lib/libcomm.h 1 / 2 @ f i l e 3 4 D e f i n i t i o n s f o r libcomm . 5 / 6 7 / 8 Copyright ( c ) Andreas Hofmeier 9 (www. an-h . de , www. an-h . de . vu , www. lgut . uni-bremen . de/an-h/) 10 11 This program i s f r e e software ; you can r e d i s t r i b u t e i t and/ or modify 12 i t under the terms of the GNU General Public License as published by 13 the Free Software Foundation ; e i t h e r version 2 of the License , or 14 ( at your option ) any l a t e r version . 15 16 This program i s d i s t r i b u t e d in the hope that i t w i l l be useful , but 17 WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 General Public License f o r more d e t a i l s . 20 21 You should have r e c e i ve d a copy of the GNU General Public License 22 along with t h i s program ; i f not , write to the Free Software 23 Foundation , Inc . , 6 7 5 Mass Ave , Cambridge , MA 02139 , USA. 24 / 25 26 27 28 //#include "md5. h" 29 #include < s t d i o . h> 30 #include < sys / types . h> 31 #include < sys / socket . h> 32 #include < n e t i n e t / in . h> 33 #include 34 35 #d e f i n e true 1 36 #d e f i n e f a l s e 0 37 38 #i f n d e f nothread 39 #include 40 #e n d i f 41 42 // d e c l a r a t i o n 43 44 // md5auth 45 // the f i r s t a u t h f i l e , which i s fould w i l l be used 46 // f i r s t a u t h f i l e . 47 #d e f i n e a u t h f i l e 0 ". / libcomm md5auth . pwd" 48 // second a u t h f i l e 49 #d e f i n e a u t h f i l e 1 "/ etc /libcomm md5auth . pwd" 50 // one char / byte which s e p e r a t e s the f i e l d in the a u t h f i l e 51 #d e f i n e a u t h f i l e f i e l d s e p e r a t o r ' : ' 52 // maxinam lenght of a l i n e in the a u t h f i l e 53 #d e f i n e a u t h f i l e m a x l i n e l e n g h t 4096 54 // how much random bytes are generated f o r the authentication 55 #d e f i n e authrandomstringsize ( i n t ) 16 56 // Define the message-type f o r the auth blocks 57 #d e f i n e authmessagetype 65535 58 A. Hofmeier, Final Year Project: Final Report 64 59 // s t r u c t u r e to s t r o e the authentication infromationen 60 s t r u c t AUTHINFO { 61 // network name 62 char netname ; 63 // l o g i n name 64 char name ; 65 // l o g i n passwd 66 char passwd ; 67 // Key f o r encryption ( not used yet ) 68 char keyencrypt ; 69 // Key f o r decryption ( not used yet ) 70 char keydecrypt ; 71 }; 72 73 i n t socket md5auth ( i n t fd , char netname , char name , 74 s t r u c t AUTHINFO l o c a l l o g i n , 75 s t r u c t AUTHINFO remotelogin ) ; 76 s t r u c t AUTHINFO getauthinfo ( char netname , char name ) ; 77 78 79 80 // socket acceept 81 #i f n d e f nothread 82 s t r u c t LIBCOMMPTHREADP { 83 void ( socket accept do )( i n t fd , i n t id , char pip , 84 s t r u c t sockaddr in t h e i r a d d r ) ; 85 86 pthread t thrd 2 ; 87 p t h r e a d a t t r t t h r d 2 a t t r ; 88 i n t sockport ; 89 i n t id ; 90 }; 91 void socket accept thread ( s t r u c t LIBCOMMPTHREADP libcommpthreadp ) ; 92 i n t socket accept ( i n t sockport , i n t id , 93 void ( socket accept do )( i n t fd , i n t id , char pip , 94 s t r u c t sockaddr in t h e i r a d d r ) ) ; 95 #e n d i f 96 97 98 // b l o c k r e c e i v e 99 #i f n d e f nothread 100 s t r u c t LIBCOMMPTHREADS { 101 void ( b l o c k c a l l d o ) ( i n t fd , i n t id , unsigned i n t type , 102 char buf , unsigned i n t size , i n t term ) ; 103 void ( b l o c k c a l l t e r m )( i n t fd , i n t id ) ; 104 105 pthread t thrd 1 ; 106 p t h r e a d a t t r t t h r d 1 a t t r ; 107 i n t fd ; 108 i n t id ; 109 i n t term ; 110 }; 111 void thread1 ( s t r u c t LIBCOMMPTHREADS libcommpthreads ) ; 112 i n t b l o c k c a l l ( i n t fd , i n t id , i n t term , 113 void ( b l o c k c a l l d o )( i n t fd , i n t id , unsigned i n t type , 114 char buf , unsigned i n t size , 115 i n t term ) , 116 void ( b l o c k c a l l t e r m )( i n t fd , i n t id ) ) ; 117 #e n d i f 118 char b l o c k r e c e i v e p o l l ( i n t fd , unsigned i n t type , char buf , 119 unsigned i n t size , unsigned i n t maxsize , 120 i n t term ) ; 121 char b l o c k r e c e i v e ( i n t fd , unsigned i n t type , char buf , 122 unsigned i n t size , unsigned i n t maxsize , 123 i n t term ) ; A. Hofmeier, Final Year Project: Final Report 65 124 i n t b l o c k r e c e i v e i n t e g e r ( i n t fd , unsigned i n t r e c v i ) ; 125 i n t b l o c k r e c e i v e n b y t e s ( i n t fd , char buf , i n t n ) ; 126 127 128 129 // block send 130 i n t block send ( i n t fd , unsigned i n t type , char buf , unsigned i n t s i z e ) ; 131 132 133 134 // block random 135 char block random ( char buf , i n t s i z e ) ; 136 137 138 139 // socket bind 140 i n t socket bind ( i n t port , i n t cqueue ) ; 141 142 143 144 // socket connect 145 i n t socket connect ( char host , i n t port ) ; 146 147 148 149 // l i n e monitor 150 s t r u c t LINEMONITOR THREAD DATA { 151 char s e r v e r ; 152 i n t port ; 153 i n t soft msec ; 154 i n t hard msec ; 155 i n t wait msec ; 156 void ( linemonitor exception )( char server , i n t port , i n t type ) ; 157 i n t sock ; 158 }; 159 160 161 void l i n e m o n i t o r s e r v e r t h r e a d ( s t r u c t LINEMONITOR THREAD DATA 162 linemonitor thread data ) ; 163 i n t l i n e m o n i t o r s e r v e r ( i n t port , 164 i n t soft msec , i n t hard msec , i n t wait msec , 165 void ( linemonitor exception )( char server , i n t port , 166 i n t type ) ) ; 167 void linemonitor emergencystop ( i n t sock ) ; 168 i n t linemonitor thread ( s t r u c t LINEMONITOR THREAD DATA 169 linemonitor thread data ) ; 170 i n t linemonitor ( char server , i n t port , 171 i n t soft msec , i n t hard msec , i n t wait msec , 172 void ( linemonitor exception )( char server , i n t port , 173 i n t type ) ) ; 174 175 10.3.2 src/lib/libcomm.c 1 / 2 @ f i l e 3 4 Main part of libcomm . 5 / 6 7 / 8 Copyright ( c ) Andreas Hofmeier A. Hofmeier, Final Year Project: Final Report 66 9 (www. an-h . de , www. an-h . de . vu , www. lgut . uni-bremen . de/an-h/) 10 11 This program i s f r e e software ; you can r e d i s t r i b u t e i t and/ or modify 12 i t under the terms of the GNU General Public License as published by 13 the Free Software Foundation ; e i t h e r version 2 of the License , or 14 ( at your option ) any l a t e r version . 15 16 This program i s d i s t r i b u t e d in the hope that i t w i l l be useful , but 17 WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 General Public License f o r more d e t a i l s . 20 21 You should have r e c e i ve d a copy of the GNU General Public License 22 along with t h i s program ; i f not , write to the Free Software 23 Foundation , Inc . , 6 7 5 Mass Ave , Cambridge , MA 02139 , USA. 24 / 25 26 27 #include < s t d i o . h> 28 #include < s t d l i b . h> 29 #include < sys / types . h> 30 #include < sys / socket . h> 31 #include < sys / time . h> 32 #include < unistd . h> 33 #include < sys / p o l l . h> 34 #include < s t r i n g . h> 35 36 37 #include "libcomm . h" 38 #include "md5. h" 39 40 #i f n d e f nothread 41 #include 42 #e n d i f 43 44 45 #i f n d e f nothread 46 / 47 This i s a part of socket accept ( ) and must not c a l l e d from the 48 user . This function i s the thread which i s s t a r t e d from 49 socket accept ( ) and runs in background . 50 / 51 void socket accept thread ( s t r u c t LIBCOMMPTHREADP libcommpthreadp ) { 52 char buf ; 53 unsigned i n t type ; 54 unsigned i n t s i z e ; 55 / connector ' s address information / 56 s t r u c t sockaddr in t h e i r a d d r ; 57 i n t s i n s i z e ; 58 i n t fd ; 59 60 while ( 1 ) { 61 // wait and accept a incomming connection 62 s i n s i z e = s i z e o f ( s t r u c t sockaddr in ) ; 63 i f ( ( fd = accept ( libcommpthreadp -> sockport , 64 ( s t r u c t sockaddr ) & their addr , 65 &s i n s i z e )) != -1) { 66 char pip = i n e t n t oa ( t h e i r a d d r . sin addr ) ; 67 68 libcommpthreadp -> socket accept do ( fd , 69 libcommpthreadp -> id , 70 pip , t h e i r a d d r ) ; 71 } 72 } 73 // pthread exit (NULL) ; A. Hofmeier, Final Year Project: Final Report 67 74 } 75 76 77 / 78 Start a new thread , wait f o r connections and s t a r t 79 socket accept do ( ) when someone connects . 80 81 @param sockport ( i n t ) d e s c r i p t o r of a tcp socket / port from 82 socket bind () 83 84 @param id ( i n t ) a r b i t r a r y id of background process / thread . ( May 85 be i t i s a good idea to use the portnumber . ) 86 87 @param aocket accept do ( i n t fd , i n t id , char pip , s t r u c t 88 sockaddr in t h e i r a d d r ) ( function ) t h i s function i s c a l l e d i f 89 somebody connects . fd i s the d e s c r i p t o r of the new socket to the 90 connected tcp-tream . id i s the same as in socket accept ( ) . pip 91 contains the ip-address of the connected c l i e n t . The s t r u c t u r e 92 t h e i r a d d r c o n t a i l s a l l known information about the connected 93 c l i e n t . 94 95 @return I f a l l r i g h t zero otherwise non zero . 96 / 97 i n t socket accept ( i n t sockport , i n t id , 98 void ( socket accept do )( i n t fd , i n t id , char pip , 99 s t r u c t sockaddr in t h e i r a d d r ) ) { 100 101 // a l l o c a t e memory f o r thread c o n f i g u r a t i o n 102 s t r u c t LIBCOMMPTHREADP libcommpthreadp ; 103 libcommpthreadp = ( s t r u c t LIBCOMMPTHREADP ) 104 malloc ( s i z e o f ( s t r u c t LIBCOMMPTHREADP) ) ; 105 i f ( libcommpthreadp == NULL) { 106 perror ( "malloc ( ) ") ; 107 return -1; 108 } 109 110 // s t o r e a l l necessary data in i t 111 libcommpthreadp -> sockport = sockport ; 112 libcommpthreadp -> id = id ; 113 libcommpthreadp -> socket accept do = socket accept do ; 114 115 // s t a r t i n g thread 116 p t h r e a d a t t r i n i t (&( libcommpthreadp -> t h r d 2 a t t r ) ) ; 117 return pthread create (&( libcommpthreadp -> thrd 2 ) , 118 &(libcommpthreadp -> t h r d 2 a t t r ) , 119 ( void ) socket accept thread , 120 libcommpthreadp ) ; 121 122 } 123 124 #e n d i f 125 126 127 / Bind a socket to a port ( Server s i d e ) . This function c r e a t e s an 128 Socket and binds i t to a l o c a l port . 129 130 @param port an i n t e g e r which s p e c i f i e s the port 131 132 @param cqueue an i n t e g e r how many pending connections queue w i l l 133 hold in the waiting queue . 134 135 @return The F i l e Descriptor (FD) which allows access to the bound 136 port . 137 / 138 A. Hofmeier, Final Year Project: Final Report 68 139 #include < n e t i n e t / in . h> 140 141 i n t socket bind ( i n t port , i n t cqueue ) { 142 // FD of the new socket to the bound port 143 i n t sock ; 144 // address information 145 s t r u c t sockaddr in ad ; 146 147 // c r e a t e a socket 148 i f ( ( sock = socket (AF INET , SOCK STREAM, 0)) == -1) { 149 // cannot created socket , return e r r o r 150 perror ( " socket ") ; 151 return -1; 152 } 153 154 // make ensure that the memory i s i n i t i a t e d 155 memset(&ad , 0 , s i z e o f ( ad ) ) ; 156 157 // address family : AF INET : IPv4 Int ernet p r o t o c o l s 158 ad . s i n f a m i l y = AF INET ; 159 // convert and copy port in s t r u c t u r e 160 ad . s i n p o r t = htons ( port ) ; 161 // bind to a l l i n t e r f a c e s -- the port w i l l accept connections to a l l 162 // addresses of the l o c a l machine 163 ad . sin addr . s addr = INADDR ANY; 164 // bind socket 165 i f ( bind ( sock , ( s t r u c t sockaddr ) & ad , s i z e o f ( s t r u c t sockaddr )) == -1) { 166 // cannot bind , return e r r o r 167 perror ( "bind ") ; 168 return -1; 169 } 170 // l i s t e n f o r connections on bound port 171 i f ( l i s t e n ( sock , cqueue ) == -1) { 172 // cannot l i s t e n , return e r r o r 173 perror ( " l i s t e n ") ; 174 return -1; 175 } 176 // a l l right , port i s l i s t e n i n g . Return the FD as 177 // r e f e r e n c e f o r use . 178 return sock ; 179 } 180 181 182 #include < n e t i n e t / in . h> 183 #include 184 #include < sys / types . h> 185 #include < sys / socket . h> 186 #include 187 188 189 190 / 191 Connect a TCP-stream to a s e r v e r ( Client s i d e ) . Creates a socket and 192 connect i t over a TCP-stream to the s p e c i f i e d port on the s p e c i f i e d 193 s e r v e r . 194 195 @param host a s t r i n g ( char ) which s p e c i f i e s the name or the 196 IP-address of the s e r v e r . 197 198 @param port an i n t e g e r which s p e c i f i e s the port on the s e r v e r . 199 200 @return The F i l e Descriptor (FD) which allows access to the 201 TCP-stream-socket or -1 i f the connection f a i l s . 202 / 203 i n t socket connect ( char host , i n t port ) { A. Hofmeier, Final Year Project: Final Report 69 204 // FD of the new socket to the TCP-stream 205 i n t sock ; 206 // The IP address in binary form 207 i n a d d r t inaddr ; 208 // address information to connect other s i d e ( s y s c a l l : connect ( ) ) 209 s t r u c t sockaddr in ad ; 210 // contains the r e s u l t of the r e s o l u t i o n of a network-name . 211 s t r u c t hostent hp ; 212 213 // make ensure that the memory i s i n i t i a t e d 214 memset(&ad , 0 , s i z e o f ( ad ) ) ; 215 // address family : AF INET : IPv4 Int ernet p r o t o c o l s 216 ad . s i n f a m i l y = AF INET ; 217 // Try to convert the given IP-address into binary data . . . 218 inaddr = inet addr ( host ) ; 219 i f ( inaddr != INADDR NONE) { 220 // i f the IP address was converted copy i t in the parameter 221 // s t r u c t u r e ( ad ) f o r l a t e r use 222 memcpy(&ad . sin addr , & inaddr , s i z e o f ( inaddr ) ) ; 223 } e l s e { 224 // i f t h i s i s not p o s s i b l e ( the name and not the IP address i s 225 // given ) , try to r e s o l v e the name to a binary IP address 226 hp = gethostbyname ( host ) ; 227 i f ( hp == NULL) { 228 // name cannot resolved , return e r r o r 229 perror ( "gethostbyname ( ) ") ; 230 return -1; 231 } 232 // copy address in the parameter s t r u c t u r e ( ad ) f o r l a t e r use 233 memcpy(&ad . sin addr , hp->h addr , hp->h length ) ; 234 } 235 // convert and copy port-number in the parameter s t r u c t u r e ( ad ) f o r 236 // l a t e r use 237 ad . s i n p o r t = htons ( port ) ; 238 // c r e a t e a socket 239 sock = socket (AF INET , SOCK STREAM, 0 ) ; 240 i f ( sock < 0) { 241 // cannot created socket , return e r r o r 242 perror ( " socket ( ) ") ; 243 return -1; 244 } 245 // connect the socket over an TCP-stream to the port and the server , 246 // which are stored in ad . 247 i f ( connect ( sock , ( s t r u c t sockaddr ) & ad , s i z e o f ( ad )) < 0) { 248 // connection i s not possible , return e r r o r 249 perror ( "connect ( ) ") ; 250 return -1; 251 } 252 // a l l right , socket i s connected an can be used . Return the FD as 253 // r e f e r e n c e f o r use . 254 return sock ; 255 } 256 257 258 / 259 Get random numbers/ bytes . This function read random numbers/ bytes 260 from / dev/urandom and s t o r t t h i s bytes in a b u f f e r . 261 262 @param buf ( char ) in which the bytes w i l l be stored . I f t h i s 263 parameter i s equal to NULL dynamic memory w i l l be a l l o c a t e d . 264 265 @param s i z e an integer , s p e c i f i e s ths s i z e of the b u f f e r ( the 266 number of the random bytes ) . WARNING: I f buf i s not equal to null , 267 n( s i z e ) bytes w i l l be stored in t h i s b u f f e r without any check of 268 ths s i z e of t h i s buf . A. Hofmeier, Final Year Project: Final Report 70 269 270 @return ( char ) a pointer to the b u f f e r in which the random bytes 271 are stored . 272 / 273 char block random ( char buf , i n t s i z e ) { 274 FILE f ; 275 276 // I f no momory allocated , a l l o c a t e memory 277 i f ( buf == NULL) { 278 i f ( ( buf = malloc ( s i z e )) == NULL) { 279 perror ( "malloc ") ; 280 return NULL; 281 } 282 } 283 284 // Read Random numbers from / dev/urandom and s t r o e t h i s these in the 285 // b u f f e r 286 287 i f ( ( f = fopen ("/ dev/urandom " , " ro ")) == NULL) { 288 perror ( "fopen (/ dev/urandom ) ") ; 289 return NULL; 290 } 291 292 fread ( buf , 1 , size , f ) ; 293 294 f c l o s e ( f ) ; 295 296 return buf ; 297 } 298 299 300 301 302 303 304 #i f n d e f nothread 305 / 306 This i s a part of b l o c k c a l l ( ) and must not c a l l e d from the 307 user . This function i s the thread which i s s t a r t e d from 308 b l o c k c a l l ( ) and runs in background . 309 310 @param libcommpthreads ( s t r u c t LIBCOMMPTHREADS ) holds p o i n t e r s to 311 the f u n c t i o n s to be c a l l , fd ( socket d i s c r i p t o r ) and id . 312 / 313 void thread1 ( s t r u c t LIBCOMMPTHREADS libcommpthreads ) { 314 char buf ; 315 unsigned i n t type ; 316 unsigned i n t s i z e ; 317 318 while ( 1 ) { 319 // try to r e c e i v e a datablock . . . 320 buf = b l o c k r e c e i v e ( libcommpthreads -> fd , & type , NULL, & size , 0 , 321 libcommpthreads -> term ) ; 322 // f a i l e d : c a l l b l o c k c a l l t e r m ( ) and terminate thread 323 i f ( buf == NULL) { 324 libcommpthreads -> b l o c k c a l l t e r m ( libcommpthreads -> fd , 325 libcommpthreads -> id ) ; 326 break ; 327 } 328 // datablock OK: c a l l b l o c k c a l l d o ( ) , a f t e r t h i s wait f o r the 329 // next datablock 330 libcommpthreads -> b l o c k c a l l d o ( libcommpthreads -> fd , 331 libcommpthreads -> id , 332 type , buf , size , 333 libcommpthreads -> term ) ; A. Hofmeier, Final Year Project: Final Report 71 334 } 335 pthread exit (NULL) ; 336 } 337 338 339 / 340 Waits in a new thread f o r a datablock to be re ceived and c a l l s the 341 function b l o c k c a l l d o ( ) i f t h i s event occurs or b l o c k c a l l t e r m () 342 when the connection terminates . 343 344 @param fd ( i n t ) d e s c r i p t o r of socket 345 346 @param id ( i n t ) a r b i t r a r y id of background process / thread 347 348 @param term ( i n t ) 0 : do not terminate the buffer , 1 : terminate the 349 b u f f e r by appending a 0 x00 . 350 351 @param b l o c k c a l l d o ( i n t fd , i n t id , unsigned i n t type , char buf , 352 unsigned i n t size , i n t term ) ( function ) t h i s function i s c a l l e d i f 353 a datablock was r e c e i ved . fd , id and term are the same as in 354 b l o c k c a l l ( ) . type d e s c r i b e s the type of the received datablock , 355 buf i s a pointer to t h i s datablock and s i z e i s the number of bytes 356 of the datablock 357 358 @param b l o c k c a l l t e r m ( i n t fd , i n t id ) ( function ) t h i s function i s 359 c a l l e d i f the connection terminates . fd and id are the same as in 360 b l o c k c a l l ( ) . 361 362 @return I f a l l r i g h t zero otherwise non zero . 363 / 364 i n t b l o c k c a l l ( i n t fd , i n t id , i n t term , 365 void ( b l o c k c a l l d o )( i n t fd , i n t id , unsigned i n t type , 366 char buf , unsigned i n t size , 367 i n t term ) , 368 void ( b l o c k c a l l t e r m )( i n t fd , i n t id ) ) { 369 370 // a l l o c a t e memory f o r thread c o n f i g u r a t i o n 371 s t r u c t LIBCOMMPTHREADS libcommpthreads ; 372 libcommpthreads = ( s t r u c t LIBCOMMPTHREADS ) 373 malloc ( s i z e o f ( s t r u c t LIBCOMMPTHREADS) ) ; 374 i f ( libcommpthreads == NULL) { 375 perror ( "malloc ( ) ") ; 376 return -1; 377 } 378 379 // s t o r e a l l necessary data in i t 380 libcommpthreads -> fd = fd ; 381 libcommpthreads -> id = id ; 382 libcommpthreads -> b l o c k c a l l d o = b l o c k c a l l d o ; 383 libcommpthreads -> b l o c k c a l l t e r m = b l o c k c a l l t e r m ; 384 385 // s t a r t i n g thread 386 p t h r e a d a t t r i n i t (&( libcommpthreads -> t h r d 1 a t t r ) ) ; 387 return pthread create (&( libcommpthreads -> thrd 1 ) , 388 &(libcommpthreads -> t h r d 1 a t t r ) , 389 ( void ) thread1 , libcommpthreads ) ; 390 } 391 392 #e n d i f 393 394 395 396 / 397 This function t e s t s i f new data i s a v a i l a b l e to read on a stream . 398 A. Hofmeier, Final Year Project: Final Report 72 399 @param fd ( i n t ) d i s c r i p t o r of stream to t e s t 400 401 @return ( i n t ) 1 : Data to read ; 0 : No data to read 402 / 403 i n t b l o c k i f d a t a ( i n t fd ) { 404 s t r u c t p o l l f d polld ; 405 406 polld . fd = fd ; 407 polld . events = POLLIN | POLLPRI; 408 409 i f ( p o l l (&polld , 1 , 0 ) ) { 410 return 1 ; 411 } 412 return 0 ; 413 } 414 415 416 / 417 Test i f i s there data a v a i l a b l e on the socket ' s input b u f f e r and 418 s t a r t s r e c e i v i n g a block i f there i s . WARNING: The i n t e g e r s ( type 419 and s i z e ; excluding fd ) are only 1 6 b i t values (0 - 65535). 420 421 @param fd ( i n t ) d e s c r i p t o r of socket 422 423 @param type ( unsigned i n t ) pointer to integer , t h i s value can be 424 used as buyer ' s option 425 426 @param buf ( char ) b u f f e r f o r datablock . Memory w i l l be a l l o c a t e d 427 i f t h i s parameter i s equal to n u l l . 428 429 @param s i z e ( unsigned i n t ) pointer to i n t e g e r in which the s i z e 430 of the r e c e i ve d datablock i s saved . 431 432 @param maxsize ( unsigned i n t ) d e s c r i b e s s i z e of buf . This 433 parameter w i l l be ignored i f bus i s equal to n u l l . 434 435 @param term ( i n t ) 0 : do not terminate the buffer , 1 : terminate the 436 b u f f e r by appending a 0 x00 . 437 438 @return ( char ) pointer to b u f f e r which contains the r eceived 439 datablock ; NULL i f f a i l ; 1 i f no data a v a i l a b l e . 440 441 / 442 char b l o c k r e c e i v e p o l l ( i n t fd , unsigned i n t type , char buf , 443 unsigned i n t size , unsigned i n t maxsize , 444 i n t term ) { 445 // new data a v a i l a b l e 446 i f ( b l o c k i f d a t a ( fd ) ) { 447 return b l o c k r e c e i v e ( fd , type , buf , size , maxsize , term ) ; 448 } e l s e { 449 // no new data a v a i l a b l e 450 return ( char ) 1 L ; 451 } 452 } 453 454 455 456 / 457 Receive a block ( composition of : type , s i z e of datablock and 458 datablock ) from a socket . Waits f o r a block to be received 459 completely . WARNING: The i n t e g e r s ( type and s i z e ; excluding fd ) are 460 only 1 6 b i t values (0 - 65535). 461 462 @param fd ( i n t ) d e s c r i p t o r of socket 463 A. Hofmeier, Final Year Project: Final Report 73 464 @param type ( unsigned i n t ) pointer to integer , t h i s value can be 465 used as buyer ' s option 466 467 @param buf ( char ) b u f f e r f o r datablock . Memory w i l l be a l l o c a t e d 468 i f t h i s parameter i s equal to n u l l . 469 470 @param s i z e ( unsigned i n t ) pointer to i n t e g e r in which the s i z e 471 of the r e c e i ve d datablock i s saved . 472 473 @param maxsize ( unsigned i n t ) d e s c r i b e s s i z e of buf . This 474 parameter w i l l be ignored i f bus i s equal to n u l l . 475 476 @param term ( i n t ) 0 : do not terminate the buffer , 1 : terminate the 477 b u f f e r by appending a 0 x00 . 478 479 @return ( char ) pointer to b u f f e r which contains the r eceived 480 datablock ; NULL i f f a i l . 481 482 / 483 char b l o c k r e c e i v e ( i n t fd , unsigned i n t type , char buf , 484 unsigned i n t size , unsigned i n t maxsize , 485 i n t term ) { 486 // do not t r u s t any user ! 487 i f ( term > 1) { 488 term = 1; 489 } 490 i f ( term < 0) { 491 term = 0; 492 } 493 494 // r e c e i v i n g type 495 i f ( b l o c k r e c e i v e i n t e g e r ( fd , type ) < 0) { 496 return NULL; 497 } 498 // r e c e i v i n g s i z e 499 i f ( b l o c k r e c e i v e i n t e g e r ( fd , s i z e ) < 0) { 500 return NULL; 501 } 502 503 i f ( buf == NULL) { 504 i f ( ( buf = ( char ) malloc ( s i z e + term )) == NULL) { 505 perror ( "malloc ( ) ") ; 506 return NULL; 507 } 508 } e l s e { 509 i f ( ( s i z e + term ) > maxsize ) { 510 f p r i n t f ( stderr , "Try to r e c e i v e more than f i t in the b u f f e r \n ") ; 511 return NULL; 512 } 513 } 514 // r e c e i v i n g data 515 i f ( b l o c k r e c e i v e n b y t e s ( fd , buf , s i z e ) < 0) { 516 return NULL; 517 } 518 519 i f ( term ) { 520 buf [ s i z e ] = 0 ; 521 } 522 523 return buf ; 524 } 525 526 527 528 A. Hofmeier, Final Year Project: Final Report 74 529 / 530 Receive an i n t e g e r ( two bytes ; 1 6 Bit ) from the socket . 531 532 @param fd ( i n t ) d e s c r i p t o r of socket 533 534 @param r e c v i ( unsigned i n t ) pointer to i n t e g e r in which the 535 r e c e i ve d i n t e g e r i s saved . 536 537 @return ( i n t ) 2 : OK; -1: f a i l 538 / 539 i n t b l o c k r e c e i v e i n t e g e r ( i n t fd , unsigned i n t r e c v i ) { 540 i n t i , r ; 541 // unsigned i n t r e c v i ; 542 i n t s i z e o f i n t = 2 ; / s i z e o f ( i n t ) ; / 543 544 // r e s e t value 545 r e c v i = 0; 546 547 // r e c e i v e value 548 i f ( recv ( fd , ( ( char ) r e c v i ) , s i z e o f i n t , MSG WAITALL) ! = s i z e o f i n t ) { 549 perror ( " recv ( ) ") ; 550 return -1; 551 } 552 553 return 2 ; / / r e c v i ; 554 } 555 556 557 558 559 / 560 Receive n bytes from socket . 561 562 @param fd ( i n t e g e r ) d e s c r i p t o r of socket 563 564 @param buf ( char ) b u f f e r f o r saving the re ceived bytes 565 566 @param n ( i n t e g e r ) number of bytes to r e c e i v e 567 568 @return ( i n t e g e r ) n : OK; -1 f i a l 569 / 570 i n t b l o c k r e c e i v e n b y t e s ( i n t fd , char buf , i n t n ) { 571 i n t i , r ; 572 unsigned i n t r e c v i ; 573 i n t s i z e o f i n t = 2 ; / s i z e o f ( i n t ) ; / 574 575 // r e c e i v e n bytes to b u f f e r 576 i f ( recv ( fd , buf , n , MSG WAITALL) ! = n ) { 577 perror ( " recv ( ) ") ; 578 return -1; 579 } 580 581 return n ; 582 } 583 584 585 586 / 587 Send a block ( composition of : type , s i z e of datablock and datablock 588 ( buf ) ) to a socket . The function blocks u n t i l the whole block i s 589 t r a n s f e r e d to the b u f f e r . I f the b u f f e r i s f u l l , data has to be 590 sent f i r s t . WARNING: The i n t e g e r s ( type and s i z e ; excluding fd ) are 591 only 1 6 b i t values (0 - 65535). 592 593 @param fd ( i n t ) d e s c r i p t o r of the socket to which buf should send A. Hofmeier, Final Year Project: Final Report 75 594 595 @param type ( unsigned i n t ) This value can be used as buyer ' s option 596 597 @param buf ( char ) which should be send 598 599 @return number of sent bytes , -1 i f an e r r o r i s occurt . 600 / 601 602 i n t block send ( i n t fd , unsigned i n t type , char buf , 603 unsigned i n t s i z e ) { 604 // add up the number of sent byte , f o r checking . 605 i n t i , r ; 606 607 // send the type of the data 608 i = r = 0; 609 while ( r < 2) { 610 i f ( ( i = send ( fd , ( void ) & type + r , 2 - r , 0 ) ) < 0 ) { 611 return -1; 612 } 613 r += i ; 614 } 615 // send the s i z e of the b u f f e r 616 i = r = 0; 617 while ( r < 2) { 618 i f ( ( i = send ( fd , ( void ) & s i z e + r , 2 - r , 0 ) ) < 0 ) { 619 return -1; 620 } 621 r += i ; 622 } 623 // send the data in the b u f f e r i t s e l f 624 i = r = 0; 625 while ( r < s i z e ) { 626 i f ( ( i = send ( fd , ( void ) buf + r , s i z e - r , 0 ) ) < 0 ) { 627 return -1; 628 } 629 r += i ; 630 } 631 632 / 633 // send the type of the data 634 i f ( ( r = send ( fd , ( void ) & type , 2 , 0 ) ) < 0 ) { 635 return -1; 636 } 637 // send the s i z e of the b u f f e r 638 i f ( ( i = send ( fd , ( void ) & size , 2 , 0 ) ) < 0 ) { 639 perror ( "send0 ( ) ") ; 640 return -1; 641 } 642 r += i ; 643 // send the data in the b u f f e r i t s e l f 644 i f ( ( i = send ( fd , buf , size , 0 ) ) < 0 ) { 645 perror ( "send1 ( ) ") ; 646 return -1; 647 } 648 r += i ; 649 650 // not the comlete messages was sent . 651 i f ( r = ( s i z e + 4)) { 652 perror ( "send2 ( ) ") ; 653 return -1; 654 } 655 / 656 657 return r ; 658 } A. Hofmeier, Final Year Project: Final Report 76 659 660 661 662 663 664 665 / 666 Free the memory space which i s used by an AUTHINFO s t r u c t u r e . 667 668 @param ( s t r u c t AUTHINFO ) pointer to s t r u c t u r e to destroy . 669 / 670 void f r e e a u t h i n f o ( s t r u c t AUTHINFO destroy ) { 671 f r e e ( destroy -> netname ) ; 672 f r e e ( destroy -> name ) ; 673 f r e e ( destroy -> passwd ) ; 674 f r e e ( destroy -> keyencrypt ) ; 675 f r e e ( destroy -> keydecrypt ) ; 676 f r e e ( destroy ) ; 677 } 678 679 680 681 / 682 Do both s i d e a u t h e n t i f i c a t i o n . This function i s usually c a l l e d 683 j u s t a f t e r a socket stream i s e s t a b l i s h e d . The function must be 684 c a l l e d on both s i d e s . Both s i d e s f o l l o w i n g these steps : 685 686 1 . get auth i n f o ( [ l o g i n ] name , passwd ) by using getauthinfo ( ) from 687 name or netname f o r remote l o g i n 688 689 2 . generate random numbers 690 691 3 . exchange ( f i r s t send , then r e c e i v e ) l o g i n names 692 693 4 . exchange random numbers 694 695 5 . c a l c u l a t e md5 checksum over the random numbers ( received from other 696 s i d e ) and the remote passwd . 697 698 6 . exchange md5 checksums 699 700 7 . get auth i n f o from name ( receive d from other s i d e ) f o r l o c a l l o g i n 701 702 8 . c a l c u l a t e md5 checksum over the l o c a l random numbers and the 703 l o c a l passwd . 704 705 9 . check l o g i n -- compare the received md5sum ( 6 . ) with the 706 generated one ( 8 . ) ; send acknowledgement 707 708 1 0 . r e c e i v e remote acknowledgement 709 710 1 1 . return s u i t a b l e values 711 712 @param fd ( i n t ) d e s c r i b e s the socket on which the authentication 713 has to be done 714 715 @param netname ( char ) use netname to r e s o l v e [ l o g i n ] name and 716 passwd of the remote machine (NULL: not s p e c i f i e d ) 717 718 @param netname ( char ) use [ l o g i n ] name to r e s o l v e passwd of the 719 remote machine (NULL: not s p e c i f i e d ; both NULL use f i r s t entry in 720 f i l e , see getauthinfo ( ) ) 721 722 @param p l o c a l l o g i n ( s t r u c t AUTHINFO ) ( pointer to pointer to an 723 AUTHINFO s t r u c t ) in t h i s ( double pointed ) s t r u c t the l o c a l authinfo A. Hofmeier, Final Year Project: Final Report 77 724 w i l l be loaded , i f the parameter i s not n u l l . 725 726 @param premotelogin ( s t r u c t AUTHINFO ) in t h i s ( double pointed ) 727 s t r u c t the remote authinfo w i l l be loaded , i f the parameter i s not 728 n u l l . 729 730 @return ( i n t ) 0 : Authentication /Login OK; -1: remote l o g i n e r r o r ; 731 -2: l o g i n e r r o r on both s i d e s ; -3: l o c a l l o g i n e r r o r ; -4: other 732 ( network ) e r r o r ; -5: cannot load remote auth i n f o ; -6: cannot load 733 l o c a l auth i n f o ; 734 / 735 i n t socket md5auth ( i n t fd , char netname , char name , 736 s t r u c t AUTHINFO p l o c a l l o g i n , 737 s t r u c t AUTHINFO premotelogin ) { 738 char r s t r 0 [ authrandomstringsize ] , r s t r 1 [ authrandomstringsize ] ; 739 char rstr0sum [ 3 5 ] , rstr1sum [ 3 5 ] ; 740 741 i n t otype ; 742 char oname ; 743 i n t onamesize ; 744 char randblock ; 745 char orandblock ; 746 i n t orandblocksize ; 747 748 s t r u c t MD5Context context ; 749 unsigned char md5 prs [ 1 6 ] ; 750 unsigned char omd5 prs [ 1 6 ] ; 751 752 i n t l o g i n o k = 0; 753 754 s t r u c t AUTHINFO l o c a l l o g i n ; 755 / / 1 . 756 s t r u c t AUTHINFO remotelogin = getauthinfo ( netname , name ) ; 757 i f ( remotelogin == NULL) { 758 return -5; 759 } 760 i f ( premotelogin != NULL) { 761 premotelogin = remotelogin ; 762 } 763 764 / / 2 . generate random block f o r l o c a l l o g i n 765 i f ( ( randblock = block random (NULL, authrandomstringsize )) 766 == NULL) { 767 i f ( premotelogin == NULL) { 768 f r e e a u t h i n f o ( remotelogin ) ; 769 } 770 return -4; 771 } 772 773 / / 3 . exchange l o g i n name 774 i f ( block send ( fd , authmessagetype , remotelogin -> name , 775 s t r l e n ( remotelogin -> name)) <= 0) { 776 i f ( premotelogin == NULL) { 777 f r e e a u t h i n f o ( remotelogin ) ; 778 } 779 f r e e ( randblock ) ; 780 return -4; 781 } 782 oname = b l o c k r e c e i v e ( fd , & otype , NULL, & onamesize , 0 , true ) ; 783 i f ( ( oname == NULL ) | | 784 ( otype != authmessagetype ) ) { 785 i f ( premotelogin == NULL) { 786 f r e e a u t h i n f o ( remotelogin ) ; 787 } 788 f r e e ( randblock ) ; A. Hofmeier, Final Year Project: Final Report 78 789 return -4; 790 } 791 792 793 / / 4 . exchange random block 794 i f ( block send ( fd , authmessagetype , randblock , 795 authrandomstringsize ) 796 <= 0) { 797 i f ( premotelogin == NULL) { 798 f r e e a u t h i n f o ( remotelogin ) ; 799 } 800 f r e e ( randblock ) ; 801 f r e e (oname ) ; 802 return -4; 803 } 804 orandblock = b l o c k r e c e i v e ( fd , & otype , NULL, 805 &orandblocksize , 0 , f a l s e ) ; 806 i f ( ( orandblock == NULL ) | | 807 ( otype != authmessagetype ) ) { 808 i f ( premotelogin == NULL) { 809 f r e e a u t h i n f o ( remotelogin ) ; 810 } 811 f r e e ( randblock ) ; 812 f r e e (oname ) ; 813 f r e e ( orandblock ) ; 814 return -4; 815 } 816 817 / / 5 . c a l c u l a t e md5 checksum over the random numbers ( rec eived from 818 // other s i d e ) and the remote passwd . 819 MD5Init(&context ) ; 820 MD5Update(&context , orandblock , orandblocksize ) ; 821 MD5Update(&context , remotelogin -> passwd , 822 s t r l e n ( remotelogin -> passwd ) ) ; 823 MD5Final ( md5 prs , & context ) ; 824 825 / / 6 . exchange md5 checkumms 826 i f ( block send ( fd , authmessagetype , md5 prs , 16) <= 0) { 827 i f ( premotelogin == NULL) { 828 f r e e a u t h i n f o ( remotelogin ) ; 829 } 830 f r e e ( randblock ) ; 831 f r e e (oname ) ; 832 f r e e ( orandblock ) ; 833 return -4; 834 } 835 i f ( ( b l o c k r e c e i v e ( fd , & otype , omd5 prs , & orandblocksize , 836 16 , f a l s e ) 837 == NULL ) | | 838 ( otype != authmessagetype ) | | 839 ( orandblocksize ! = 1 6 ) ) { 840 i f ( premotelogin == NULL) { 841 f r e e a u t h i n f o ( remotelogin ) ; 842 } 843 f r e e ( randblock ) ; 844 f r e e (oname ) ; 845 f r e e ( orandblock ) ; 846 return -4; 847 } 848 usleep ( 1 ) ; 849 850 / / 7 . get auth i n f o from name ( r eceived from other s i d e ) f o r l o c a l l o g i n 851 l o c a l l o g i n = getauthinfo (NULL, oname ) ; 852 i f ( l o c a l l o g i n == NULL) { 853 i f ( premotelogin == NULL) { A. Hofmeier, Final Year Project: Final Report 79 854 f r e e a u t h i n f o ( remotelogin ) ; 855 } 856 f r e e ( randblock ) ; 857 f r e e (oname ) ; 858 f r e e ( orandblock ) ; 859 return -6; 860 } 861 i f ( p l o c a l l o g i n != NULL) { 862 p l o c a l l o g i n = l o c a l l o g i n ; 863 } 864 865 / / 8 . c a l c u l a t e md5 checksum over the l o c a l random numbers and the 866 // l o c a l passwd . 867 MD5Init(&context ) ; 868 MD5Update(&context , randblock , authrandomstringsize ) ; 869 MD5Update(&context , l o c a l l o g i n -> passwd , 870 s t r l e n ( l o c a l l o g i n -> passwd ) ) ; 871 MD5Final ( md5 prs , & context ) ; 872 873 / / 9 . check l o g i n -- compare the received md5sum ( 6 . ) with the 874 // generated one ( 8 . ) ; send acknowledgement 875 i f (memcmp( md5 prs , omd5 prs , 16) == 0) { 876 l o g i n o k = 1; 877 i f ( block send ( fd , authmessagetype , "OK", 2) <= 0) { 878 i f ( p l o c a l l o g i n == NULL) { 879 f r e e a u t h i n f o ( l o c a l l o g i n ) ; 880 } 881 i f ( premotelogin == NULL) { 882 f r e e a u t h i n f o ( remotelogin ) ; 883 } 884 f r e e ( randblock ) ; 885 f r e e (oname ) ; 886 f r e e ( orandblock ) ; 887 return -4; 888 } 889 } e l s e { 890 i f ( block send ( fd , authmessagetype , "FAIL", 4) <= 0) { 891 i f ( p l o c a l l o g i n == NULL) { 892 f r e e a u t h i n f o ( l o c a l l o g i n ) ; 893 } 894 i f ( premotelogin == NULL) { 895 f r e e a u t h i n f o ( remotelogin ) ; 896 } 897 f r e e ( randblock ) ; 898 f r e e (oname ) ; 899 f r e e ( orandblock ) ; 900 return -4; 901 } 902 } 903 904 / / 1 0 . r e c e i v e remote acknowledgement 905 f r e e ( orandblock ) ; 906 orandblock = b l o c k r e c e i v e ( fd , & otype , NULL, & orandblocksize , 907 0 , true ) ; 908 i f ( ( orandblock == NULL ) | | 909 ( otype != authmessagetype ) | | 910 ( orandblocksize ! = 2 ) | | 911 ( strcmp ( orandblock , "OK") ! = 0 ) ) { 912 i f ( l o g i n o k ) { 913 i f ( p l o c a l l o g i n == NULL) { 914 f r e e a u t h i n f o ( l o c a l l o g i n ) ; 915 } 916 i f ( premotelogin == NULL) { 917 f r e e a u t h i n f o ( remotelogin ) ; 918 } A. Hofmeier, Final Year Project: Final Report 80 919 f r e e ( randblock ) ; 920 f r e e (oname ) ; 921 return -1; 922 } e l s e { 923 i f ( p l o c a l l o g i n == NULL) { 924 f r e e a u t h i n f o ( l o c a l l o g i n ) ; 925 } 926 i f ( premotelogin == NULL) { 927 f r e e a u t h i n f o ( remotelogin ) ; 928 } 929 f r e e ( randblock ) ; 930 f r e e (oname ) ; 931 return -2; 932 } 933 } 934 935 936 i f ( p l o c a l l o g i n == NULL) { 937 f r e e a u t h i n f o ( l o c a l l o g i n ) ; 938 } 939 i f ( premotelogin == NULL) { 940 f r e e a u t h i n f o ( remotelogin ) ; 941 } 942 f r e e ( randblock ) ; 943 f r e e (oname ) ; 944 f r e e ( orandblock ) ; 945 946 i f ( ! l o g i n o k ) { 947 return -3; 948 } 949 950 // a l l r i g h t ! 951 return 0 ; 952 } 953 954 955 956 / 957 Load authentication informations ( netname , name , passwd , 958 keyencrypt , keydecrypt ) from a u t h f i l e . 959 960 @param netname ( char ) s p e c i f y the network name ( may IP ) . NULL not 961 s p e c i f i e d . 962 963 @param name ( char ) s p e c i t y the l o g i n name . NULL not 964 s p e c i f i e d . 965 966 @return ( s t r u c t AUTHINFO ) the f i r s t entry from a u t h f i l e which 967 matches network name OR l o g i n name . I f both values are NULL, the 968 f i r s t entry of the a u t h f i l e i s given back . 969 / 970 s t r u c t AUTHINFO getauthinfo ( char netname , char name ) { 971 // Descriptor f o r a u t h f i l e 972 FILE f ; 973 // b u f f e r f o r reading one l i n e of the a u t h f i l e 974 char buf [ a u t h f i l e m a x l i n e l e n g h t ] ; 975 // number of f i e l d s in the a u t h f i l e 976 i n t f i e l d s = 5; 977 // pointer b u f f e r f o r the f i v e parts of the l i n e 978 char b u f s p l i t [ f i e l d s ] ; 979 // char b u f s p l i t ; 980 // c o n t r o l variable , count v a r i a b l e f o r f i e l d 981 i n t i , j ; 982 s t r u c t AUTHINFO load ; 983 // temporary pointer A. Hofmeier, Final Year Project: Final Report 81 984 char s ; 985 986 // b u f s p l i t = ( char ) malloc ( s i z e o f ( char ) f i e l d s ) ; 987 988 // a l l o c a t e memory f o r auth-s t r u c t u r e 989 load = ( s t r u c t AUTHINFO ) malloc ( s i z e o f ( s t r u c t AUTHINFO) ) ; 990 i f ( load == NULL) { 991 perror ( "malloc ( s i z e o f ( s t r u c t AUTHINFO) ) ") ; 992 return NULL; 993 } 994 995 // open a u t h f i l e 996 i f ( ( f = fopen ( a u t h f i l e 0 , " ro ")) == NULL) { 997 perror ( a u t h f i l e 0 ) ; 998 i f ( ( f = fopen ( a u t h f i l e 1 , " ro ")) == NULL) { 999 perror ( a u t h f i l e 0 ) ; 1000 f r e e ( load ) ; 1001 return NULL; 1002 } 1003 } 1004 1005 // read as long as ther i s no more data 1006 while ( ! f e o f ( f ) ) { 1007 // read one l i n e 1008 f g e t s ( buf , a u t h f i l e m a x l i n e l e n g h t - 1 , f ) ; 1009 1010 // s p l i t the l i n e into i t f i v e components 1011 j = 0; 1012 b u f s p l i t [ j ++] = buf ; 1013 // load -> netname = buf ; 1014 f o r ( i = 0 ; i < a u t h f i l e m a x l i n e l e n g h t ; i ++) { 1015 i f ( buf [ i ] == a u t h f i l e f i e l d s e p e r a t o r ) { 1016 buf [ i ] = 0 ; 1017 i f ( j == f i e l d s ) { 1018 break ; 1019 } 1020 b u f s p l i t [ j ++] = buf + i + 1; 1021 } 1022 } 1023 1024 // i f t h i s the r i g h t entry ? Compare with parameter . 1025 i f ( 1026 ( ( name != NULL) && ( strcmp ( name , b u f s p l i t [1]) == 0)) 1027 | | 1028 ( ( netname != NULL) && ( strcmp ( netname , b u f s p l i t [0]) == 0)) 1029 | | 1030 ( ( netname == NULL) && (name == NULL)) 1031 ) { 1032 1033 // a l l o c a t e Memory 1034 f o r ( i = 0 ; i < f i e l d s ; i ++) { 1035 s = NULL; 1036 s = ( char ) malloc ( s t r l e n ( b u f s p l i t [ i ] ) + 1 ) ; 1037 i f ( s == NULL) { 1038 perror ( "malloc ( ) ") ; 1039 f r e e ( load ) ; 1040 return NULL; 1041 } 1042 strcpy ( s , b u f s p l i t [ i ] ) ; 1043 b u f s p l i t [ i ] = s ; 1044 } 1045 1046 // s t o r e the p o i n t e r s in the s t r u c t 1047 load -> netname = b u f s p l i t [ 0 ] ; 1048 load -> name = b u f s p l i t [ 1 ] ; A. Hofmeier, Final Year Project: Final Report 82 1049 load -> passwd = b u f s p l i t [ 2 ] ; 1050 load -> keyencrypt = b u f s p l i t [ 3 ] ; 1051 load -> keydecrypt = b u f s p l i t [ 4 ] ; 1052 1053 // return the pointer to t h i s s t r u c t 1054 return load ; 1055 } 1056 } 1057 f r e e ( load ) ; 1058 return NULL; 1059 } 1060 1061 1062 1063 1064 / 1065 Thread used by l i n e m o n i t o r s e r v e r ( ) NOT f o r d i r e c t usage . 1066 / 1067 void l i n e m o n i t o r s e r v e r t h r e a d ( s t r u c t LINEMONITOR THREAD DATA 1068 linemonitor thread data ) { 1069 unsigned char buf ; 1070 1071 // c o n f i g u r a t i o n of p o l l -- waiting f o r an event of the socket . 1072 s t r u c t p o l l f d polld ; 1073 polld . fd = linemonitor thread data -> sock ; 1074 polld . events = POLLIN | POLLPRI; 1075 1076 while ( 1 ) { 1077 // Receive a Ping/Byte 1078 i f ( recv ( linemonitor thread data -> sock , ( ( char ) & buf ) , 1 , 1079 MSG WAITALL) ! = 1 ) { 1080 linemonitor thread data -> linemonitor exception ( 1081 linemonitor thread data -> server , 1082 linemonitor thread data -> port , 0 ) ; 1083 break ; 1084 } 1085 // And Send i t Back 1086 i f ( send ( linemonitor thread data -> sock , & buf , 1 , 0 ) ! = 1 ) { 1087 linemonitor thread data -> linemonitor exception ( 1088 linemonitor thread data -> server , 1089 linemonitor thread data -> port , 0 ) ; 1090 break ; 1091 } 1092 1093 // Test , i f next Ping i s received within the reload -time plus 1094 // soft -timeout 1095 i f ( p o l l (&polld , 1 , linemonitor thread data -> wait msec ) 1096 <= 0) { 1097 1098 i f ( p o l l (&polld , 1 , linemonitor thread data -> soft msec ) 1099 <= 0) { 1100 // I f not , c a l l exception-function 1101 linemonitor thread data -> linemonitor exception ( 1102 linemonitor thread data -> server , 1103 linemonitor thread data -> port , 1 ) ; 1104 1105 // and t e s t i f the data i s received within the hard-timeout 1106 i f ( p o l l (&polld , 1 , linemonitor thread data -> hard msec ) 1107 <= 0) { 1108 // I f not , c a l l exception-function 1109 linemonitor thread data -> linemonitor exception ( 1110 linemonitor thread data -> server , 1111 linemonitor thread data -> port , 2 ) ; 1112 } 1113 } A. Hofmeier, Final Year Project: Final Report 83 1114 } 1115 } 1116 1117 pthread exit (NULL) ; 1118 } 1119 1120 1121 1122 / 1123 Monitor i f the " l i n e " i s f a s t enough : Server Application . This 1124 function opens a port and wait f o r the f i r s t connection on t h i s 1125 port . All data / pings which i s sent bei t h i s f i r s t connection w i l l 1126 be sent back . The soft -timeout w i l l c a l l e d a f t e r wait msec AND 1127 soft msec i s timeouted . The hard-timeout w i l l c a l l e d a f t e r 1128 soft -timeout was c a l l e d AND hard msec i s timeouted . 1129 1130 @param port ( i n t ) port which should be l i s t e n d 1131 1132 @param soft msec ( i n t ) timeout in m i l l i s e c o n d s which causes 1133 soft -real -time exception . 1134 1135 @param hard msec ( i n t ) timeout in m i l l i s e c o n d s which causes 1136 hard-real -time exception . 1137 1138 @param wait msec ( i n t ) timeout f o r resent -- sending of the next 1139 ping . 1140 1141 @param linemonitor exception ( pointer to function ) This function 1142 w i l l be c a l l e d i f an exception occurs . I t becomes the f o l l o w i n g 1143 parameters : s e r v e r name ( char ) which i s always null , port ( i n t ) : 1144 l i s t e n d port and type ( i n t ) of exception which can be : 0 : Connicion 1145 Fault , 1 : Soft Real Time Exception , 2 : HARD Real Time Exception . 1146 1147 @return ( i n t ) F i l e d i s c r i p t o r to the used socket . Only f o r usage 1148 with linemonitor emergencystop ( ) . 1149 / 1150 i n t l i n e m o n i t o r s e r v e r ( i n t port , 1151 i n t soft msec , i n t hard msec , i n t wait msec , 1152 void ( linemonitor exception )( char server , i n t port , 1153 i n t type ) ) { 1154 i n t sock ; 1155 1156 / connector ' s address information / 1157 s t r u c t sockaddr in t h e i r a d d r ; 1158 i n t s i n s i z e ; 1159 i n t fd ; 1160 1161 // ID and a t r i b u t e s f o r the threads 1162 pthread t thrd 2 ; 1163 p t h r e a d a t t r t t h r d 2 a t t r ; 1164 1165 // a l l o c a t e memory to s t o r e parameter f o r the 1166 // l i n e m o n i t o r s e r v e r t h r e a d ( ) function . 1167 s t r u c t LINEMONITOR THREAD DATA linemonitor thread data ; 1168 linemonitor thread data = ( s t r u c t LINEMONITOR THREAD DATA ) 1169 malloc ( s i z e o f ( s t r u c t LINEMONITOR THREAD DATA) ) ; 1170 i f ( linemonitor thread data == NULL) { 1171 perror ( "malloc ( ) ") ; 1172 return -1; 1173 } 1174 1175 // s t o r e a l l necessary parameters in t h i s memory 1176 linemonitor thread data -> s e r v e r = NULL; 1177 linemonitor thread data -> port = port ; 1178 linemonitor thread data -> soft msec = soft msec ; A. Hofmeier, Final Year Project: Final Report 84 1179 linemonitor thread data -> hard msec = hard msec ; 1180 linemonitor thread data -> wait msec = wait msec ; 1181 linemonitor thread data -> linemonitor exception = 1182 linemonitor exception ; 1183 1184 // Bind a port 1185 sock = socket bind ( port , 1 0 ) ; 1186 1187 // wait f o r the f i r s t connection 1188 // only accept the f i r s t connection 1189 s i n s i z e = s i z e o f ( s t r u c t sockaddr in ) ; 1190 i f ( ( fd = accept ( sock , ( s t r u c t sockaddr ) & their addr , 1191 &s i n s i z e )) != -1) { 1192 char pip = i n e t n t o a ( t h e i r a d d r . sin addr ) ; 1193 1194 linemonitor thread data -> sock = fd ; 1195 1196 // s t a r t i n g l i n e m o n i t o r s e r v e r t h r e a d () 1197 p t h r e a d a t t r i n i t (& t h r d 2 a t t r ) ; 1198 i f ( pthread create (&thrd 2 , 1199 &thrd 2 attr , 1200 ( void ) li nemo nit or se rve r th rea d , 1201 linemonitor thread data ) ! = 0 ) { 1202 return -1; 1203 } 1204 1205 return fd ; 1206 } 1207 1208 return -1; 1209 } 1210 1211 1212 1213 / 1214 Sends an "Emergency Stop " to the c l i e n t ' s side , linemonitor ( ) w i l l 1215 produce an "Emergency Stop " exception ( type 4 ) . 1216 / 1217 void linemonitor emergencystop ( i n t sock ) { 1218 unsigned char data = 254; 1219 send ( sock , & data , 1 , 0 ) ; 1220 } 1221 1222 1223 1224 / 1225 Thread used by linemonitor ( ) NOT f o r d i r e c t usage . 1226 / 1227 i n t linemonitor thread ( s t r u c t LINEMONITOR THREAD DATA 1228 linemonitor thread data ) { 1229 // b u f f e r f o r sending a ping 1230 unsigned char counter ; 1231 // b u f f e r f o r r e c e i v i n g a ping 1232 unsigned char rcounter ; 1233 1234 // c o n f i g u r a t i o n of p o l l -- waiting f o r an event of the socket . 1235 s t r u c t p o l l f d polld ; 1236 polld . fd = linemonitor thread data -> sock ; 1237 polld . events = POLLIN | POLLPRI; 1238 1239 1240 while ( 1 ) { 1241 // i n c r e a s e counter , prevent "Emergency Stop"-Code 254 1242 counter++; 1243 i f ( counter == 254) { A. Hofmeier, Final Year Project: Final Report 85 1244 counter = 0; 1245 } 1246 1247 // send a ping 1248 i f ( send ( linemonitor thread data -> sock , & counter , 1 , 0 ) ! = 1 ) { 1249 linemonitor thread data -> linemonitor exception ( 1250 linemonitor thread data -> server , 1251 linemonitor thread data -> port , 0 ) ; 1252 break ; 1253 } 1254 1255 // Test , i f Ping returns within the soft -timeout time , i f not 1256 // cause exception 1257 i f ( p o l l (&polld , 1 , linemonitor thread data -> soft msec ) <= 0) { 1258 linemonitor thread data -> linemonitor exception ( 1259 linemonitor thread data -> server , 1260 linemonitor thread data -> port , 1 ) ; 1261 // Test , i f Ping returns within the soft -timeout plus 1262 // hard-timeout time , i f not cause exception 1263 i f ( p o l l (&polld , 1 , linemonitor thread data -> hard msec ) <= 0) { 1264 linemonitor thread data -> linemonitor exception ( 1265 linemonitor thread data -> server , 1266 linemonitor thread data -> port , 2 ) ; 1267 } 1268 } 1269 1270 // r e c e i v e the ping 1271 i f ( recv ( linemonitor thread data -> sock , ( ( char ) & rcounter ) , 1 , 1272 MSG WAITALL) ! = 1 ) { 1273 linemonitor thread data -> linemonitor exception ( 1274 linemonitor thread data -> server , 1275 linemonitor thread data -> port , 0 ) ; 1276 break ; 1277 } 1278 1279 // I f "Emergency Stop " code was received , c a l l "Emergency Stop " 1280 // exception and r e t r y to r e c e i v e a ping 1281 i f ( rcounter == 254) { 1282 linemonitor thread data -> linemonitor exception ( 1283 linemonitor thread data -> server , 1284 linemonitor thread data -> port , 4 ) ; 1285 1286 i f ( recv ( linemonitor thread data -> sock , ( ( char ) & rcounter ) , 1287 1 , MSG WAITALL) ! = 1 ) { 1288 linemonitor thread data -> linemonitor exception ( 1289 linemonitor thread data -> server , 1290 linemonitor thread data -> port , 0 ) ; 1291 break ; 1292 } 1293 } 1294 1295 // Test on r i g h t transmission code and c a l l " Transmission Fault " 1296 // exception i f the data i s currupted 1297 i f ( counter != rcounter ) { 1298 linemonitor thread data -> linemonitor exception ( 1299 linemonitor thread data -> server , 1300 linemonitor thread data -> port , 3 ) ; 1301 } 1302 1303 // Wait before sendin next ping 1304 i f ( p o l l (&polld , 1 , linemonitor thread data -> wait msec ) <= 0) { 1305 } 1306 } 1307 1308 pthread exit (NULL) ; A. Hofmeier, Final Year Project: Final Report 86 1309 } 1310 1311 1312 1313 / 1314 Monitor i f the " l i n e " i s f a s t enough : Client /Robot Application . This 1315 function opens a socket stream , sents pings / bytes and wait f o r them 1316 to come back . The soft -timeout w i l l c a l l e d a f t e r soft msec i s 1317 timeouted . The hard-timeout w i l l c a l l e d a f t e r soft -timeout was 1318 c a l l e d AND hard msec i s timeouted . wait msec s p e c i f i e s the time 1319 which i s waited a f t e r a ping i s received befor the next one w i l l be 1320 launched . 1321 1322 @param s e r v e r ( char ) s e r v e r to be connected 1323 1324 @param port ( i n t ) port to be connected 1325 1326 @param soft msec ( i n t ) timeout in m i l l i s e c o n d s which causes 1327 soft -real -time exception . 1328 1329 @param hard msec ( i n t ) timeout in m i l l i s e c o n d s which causes 1330 hard-real -time exception . 1331 1332 @param wait msec ( i n t ) timeout f o r resent -- sending of the next 1333 ping . 1334 1335 @param linemonitor exception ( pointer to function ) This function 1336 w i l l be c a l l e d i f an exception occurs . I t becomes the f o l l o w i n g 1337 parameters : s e r v e r name ( char ) which i s always null , port ( i n t ) : 1338 l i s t e n d port and type ( i n t ) of exception which can be : 0 : Connicion 1339 Fault , 1 : Soft Real Time Exception , 2 : HARD Real Time Exception , 3 : 1340 Transmission Fault , 4 : Emergency Stop . 1341 / 1342 i n t linemonitor ( char server , i n t port , 1343 i n t soft msec , i n t hard msec , i n t wait msec , 1344 void ( linemonitor exception )( char server , i n t port , 1345 i n t type ) ) { 1346 1347 // ID and a t r i b u t e s f o r the threads 1348 pthread t thrd 2 ; 1349 p t h r e a d a t t r t t h r d 2 a t t r ; 1350 1351 // a l l o c a t e memory to s t o r e parameter f o r the 1352 // linemonitor thread ( ) function . 1353 s t r u c t LINEMONITOR THREAD DATA linemonitor thread data ; 1354 linemonitor thread data = ( s t r u c t LINEMONITOR THREAD DATA ) 1355 malloc ( s i z e o f ( s t r u c t LINEMONITOR THREAD DATA) ) ; 1356 i f ( linemonitor thread data == NULL) { 1357 perror ( "malloc ( ) ") ; 1358 return -1; 1359 } 1360 1361 // connect to s e r v e r 1362 linemonitor thread data -> sock = socket connect ( server , port ) ; 1363 i f ( linemonitor thread data -> sock <= 0) { 1364 linemonitor exception ( server , port , 0 ) ; 1365 return -1; 1366 } 1367 1368 // s t o r e a l l necessary parameters in t h i s memory 1369 linemonitor thread data -> s e r v e r = s e r v e r ; 1370 linemonitor thread data -> port = port ; 1371 linemonitor thread data -> soft msec = soft msec ; 1372 linemonitor thread data -> hard msec = hard msec ; 1373 linemonitor thread data -> wait msec = wait msec ; A. Hofmeier, Final Year Project: Final Report 87 1374 linemonitor thread data -> linemonitor exception = 1375 linemonitor exception ; 1376 1377 // launch linemonitor thread () 1378 p t h r e a d a t t r i n i t (& t h r d 2 a t t r ) ; 1379 return pthread create (&thrd 2 , 1380 &thrd 2 attr , 1381 ( void ) linemonitor thread , 1382 linemonitor thread data ) ; 1383 } 1384 10.4 API of the Interface interface.c(3) interface.c(3) NAME interface.c - Implementation of an example interface to a simple robot with two independent axies. SYNOPSIS #include #include #include #include #include #include Defines #define interface ymax time 20000 Time it rakes to drive to robot form y min to y max. #define interface xmax time 20000 Time it rakes to drive to robot form x min to x max. #define interface ymax 100 Maximal Y value (cosidered as 100 percent). #define interface xmax 100 Maximal X value (cosidered as 100 percent). #define interface ioport 0x378 IO Port to which lowest nible to robot is connected. Functions unsigned char input (int addr) Read a byte from an IO port. unsigned char output (int addr, unsigned char out) A. Hofmeier, Final Year Project: Final Report 88 Write a byte to an IO port. void msleep (int msec) Wait a specified number of milliseconds. int getmax (int a, int b) Get to highest number out of two input numbers. int getmin (int a, int b) Get to lowest number out of two input numbers. void interface drive (int h, int v) Drive the robot in a specified direction. void interface init (int mode) Initialze the interface and drive the robot to the start position. void interface driveto (int x, int y) Drive to robot to absolute coordinates. void interface stop () Stop the interface, switch all off. Variables int interface x current X possition of robot (global). int interface y current X possition of robot (global). int interface mode mode of interface: 0: normal, 1: simulation (do all except to drive the robot), 2: simulation with position-output 3: Blocked: Do nothing. DETAILED DESCRIPTION Implementation of an example interface to a simple robot with two independent axies. The robot has four inputs whish are connected to the lower nible on IO port 'interface_ioport'. The bits are connected in this way (the signals a high-active): Bit 0: Drive Up wires: switch to GND: yellow-green; +24V: gray-black Bit 1: Dirve down wires: switch to GND: red-green; +24V: orange-black Bit 2: Dirve right wires: switch to GND: green-red; +24V: yellow-black A. Hofmeier, Final Year Project: Final Report 89 Bit 3: Dirve left wires: switch to GND: white-red; +24V: red-blue power wires: GND: blue; +24V: red This interface assumes a linear dependency betwenn the coverence of distance and moving time. The 0,0 coordinates is left,bottom. User functions are: interface init() - Initialze the interface and drive the robot to the start position (X=undefined; Y=0). interface driveto(int x, int y) - Drive the robot to the absolute coordinates x,y. DEFINE DOCUMENTATION define interface ioport 0x378 IO Port to which lowest nible to robot is connected. define interface xmax 100 Maximal X value (cosidered as 100 percent). define interface xmax time 20000 Time it rakes to drive to robot form x_min to x_max. define interface ymax 100 Maximal Y value (cosidered as 100 percent). define interface ymax time 20000 Time it rakes to drive to robot form y_min to y_max. FUNCTION DOCUMENTATION int getmax (int a, int b) Get to highest number out of two input numbers. Parameters: A. Hofmeier, Final Year Project: Final Report 90 a (int) first input number b (int) second input number Returns: (int) the highest of the input numbers int getmin (int a, int b) Get to lowest number out of two input numbers. Parameters: a (int) first input number b (int) second input number Returns: (int) the lowest of the input numbers unsigned char input (int addr) Read a byte from an IO port. Parameters: addr (int): address of port to read Returns: (unsigned char) read byte void interface drive (int h, int v) Drive the robot in a specified direction. Any axies can be zero, greater than zero or less than zero, in this cases the robot will not driven, driven to increase to position (up[v,y] or right[h,x]) and decrease the position (down[-v,-y] or left[-h,-x]). Parameters: h (int) horizontal or X axias. v (int) vertical or Y axias. void interface driveto (int x, int y) Drive to robot to absolute coordinates. A. Hofmeier, Final Year Project: Final Report 91 Parameters: x (int): absolute x coordinate y (int): absolute y coordinate void interface init (int mode) Initialze the interface and drive the robot to the start position. void interface stop () Stop the interface, switch all off. void msleep (int msec) Wait a specified number of milliseconds. Parameters: msec (int): milliseconds to wait unsigned char output (int addr, unsigned char out) Write a byte to an IO port. Parameters: addr (int): address of port to write onto out (unsigned char): byte to write Returns: (unsigned char) written byte VARIABLE DOCUMENTATION int interface mode mode of interface: 0: normal, 1: simulation (do all except to drive the robot), 2: simulation with position-output 3: Blocked: Do nothing. int interface x current X possition of robot (global). A. Hofmeier, Final Year Project: Final Report 92 int interface y current X possition of robot (global). AUTHOR Generated automatically by Doxygen for Hofmeier_FYP:libcomm from the source code. Hofmeier_FYP:libcomm 11 Apr 2005 interface.c(3) 10.5 Source Code of the Interface 10.5.1 src/example/interface.c 1 / 2 @ f i l e 3 4 Implementation of an example i n t e r f a c e to a simple robot with two 5 independent a x i e s . The robot has four inputs whish are connected to 6 the lower n i b l e on IO port " i n t e r f a c e i o p o r t ". The b i t s are 7 connected in t h i s way ( the s i g n a l s a high-a c t i v e ) : 8 9 Bit 0 : Drive Up 10 wires : switch to GND: yellow-green ; +24V: gray-black 11 12 Bit 1 : Dirve down 13 wires : switch to GND: red-green ; +24V: orange-black 14 15 Bit 2 : Dirve r i g h t 16 wires : switch to GND: green-red ; +24V: yellow-black 17 18 Bit 3 : Dirve l e f t 19 wires : switch to GND: white-red ; +24V: red-blue 20 21 power wires : GND: blue ; +24V: red 22 23 This i n t e r f a c e assumes a l i n e a r dependency betwenn the coverence of 24 distance and moving time . The 0 , 0 coordinates i s l e f t , bottom . 25 26 User f u n c t i o n s are : 27 28 i n t e r f a c e i n i t () - I n i t i a l z e the i n t e r f a c e and drive the robot to 29 the s t a r t p o s i t i o n (X=undefined ; Y=0). 30 31 i n t e r f a c e d r i v e t o ( i n t x , i n t y) - Drive the robot to the absolute 32 coordinates x , y . 33 / 34 35 / 36 Copyright ( c ) Andreas Hofmeier A. Hofmeier, Final Year Project: Final Report 93 37 (www. an-h . de , www. an-h . de . vu , www. lgut . uni-bremen . de/an-h/) 38 39 This program i s f r e e software ; you can r e d i s t r i b u t e i t and/ or modify 40 i t under the terms of the GNU General Public License as published by 41 the Free Software Foundation ; e i t h e r version 2 of the License , or 42 ( at your option ) any l a t e r version . 43 44 This program i s d i s t r i b u t e d in the hope that i t w i l l be useful , but 45 WITHOUT ANY WARRANTY; without even the implied warranty of 46 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 47 General Public License f o r more d e t a i l s . 48 49 You should have r e c e i ve d a copy of the GNU General Public License 50 along with t h i s program ; i f not , write to the Free Software 51 Foundation , Inc . , 6 7 5 Mass Ave , Cambridge , MA 02139 , USA. 52 / 53 54 55 #include < s t d i o . h> 56 #include < unistd . h> 57 #include < s t d l i b . h> 58 #include 59 #include