Deadlines

First deadline: 14th of September
Final deadline: 21st of September

Information about how to run the lab remotely or in Windows can be found here.

Lab 1

In this assignment you will write a program to control two trains. The purpose is to write the program so that the trains move relatively independently of each other, but without colliding. Instead of a real railway, we have a simulator, where one can control the speeds of trains and change rail switches. The simulator gives a signal when a train passes sensors suitably placed on the tracks. It is part of the assignment to decide where sensors should be placed to give sufficient information for your program. The map without sensors looks as follows.

Choice of programming language

In this assignment you must use Java.

Important

In order to make sure you are using the right version of Java and train simulator, do not forget to run

setup_course tda381

on Chalmers GNU/Linux machines.


Assignment

Your assignment is to write a program that controls the trains. The trains should run simultaneously between the two stations (note that each station has two tracks). It is important that the trains are able to move at the same time, and be as independent from each other as possible, without crashing. At the stations the trains should stop and then wait 1 to 2 seconds. The trains should run forever between the stations.

In the beginning there are no sensors on the tracks. You must find where it is suitable to place sensors so that the control program gets the necessary information.

The program that you deliver should work as follows. Each train should be controlled by an independent train program, which runs in its own Java thread. Train programs cannot communicate with outside world by anything else than acquiring and releasing semaphores. In particular, no shared variables should be read or changed by the train programs. Also, both trains must use the same 'train program', and it is not allowed to make the behaviour of a train depend on its train id. For example, the track that a train chooses should not depend on its train id.

Below is a list of more detailed requirements.

Requirements


Train simulator

The simulator is called tsim and with this program you can even modify the train map. You can run tsim as follows:

tsim as a map editor

You need to get your own copy of the map in order to be able to add the sensors. The map you will be working on is that shown above.

The map file is found in the downloads section. Download it to your working directory (we strongly recommend that you create a subdirectory lab1 for your work with this assignment).

Then you can modify the map by writing tsim Lab1.map. The figure below shows how to use tsim. You should only select the sensor button in the tools window (the small T-like symbol) and then use the mouse to place sensors on the track.

tsim as a simulator

You may start tsim and interact with it using commands on standard input. Try for example the commands

SetSpeed 1 20
SetSwitch 17 7 RightSwitch

and see what happens. (The second command is necessary for the train to survive the first switch which initially is set in the wrong direction). The tsim language interfaces handle the communication with tsim and let you change the speed of the trains and the state of the switches in a more convenient way.

Here are some things to note about the simulator:

How your program communicates with the simulator

The simulator and your program run as separate OS processes. They use pipes to communicate. We will have two-way communication, so we will need two pipes. See the figure below.

You can join together two programs in the above way with the special command 2. This command starts the two commands which are given as arguments, and joins the output (stdout) of one to the input (stdin) of the other.

$ 2 "tsim Lab1.map" "java Lab1 10 5"

where Lab1 is the class containing your solution.

Note on debugging

Since both the standard I/O channels are in use, if you want to write something to the screen (for example, to help with debugging), you must use System.err.println(String s).


Program/Simulator interaction

All commands between the your program and the simulator are sent line-by-line as text strings, as you saw above. To aid you in your assignment we provide you with a Java library (TSim) that implements the protocol tsim is using. You must use this Java library. The package provides you with an interface to control the behaviour of the trains and switches. The package is available in the downloads section below.

The Java TSim contains a collection of classes to be used when communicating with the simulator from Java. You can view the JavaDoc documentation of the all interface classes here.

Usage

You cannot create instances of TSimInterface using its constructor, since it is private. Instead you use the static method getInstance() that creates an instance of the class if that has not already been done (singleton pattern).

TSimInterface tsi = TSimInterface.getInstance() ;

Interesting classes

Downloads

To start you need to download these two files:

If you wish to work on this assignment on your own computer, then you can download the files needed using the links below. Note that we do not have any experience trying to make the simulator work on windows, it will probably be quite difficult and we do not provide any help for that, but it is known to work on Mac and Linux. However, should you succeed, we would be happy to hear about it. In this case, you will also need these files:

To unzip and untar the packages use for example (or read the man page of tar and gzip):

$ gzip -dc filename_goes_here.tar.gz | tar xvf -

Tips and Tricks

Note!

It was stated above but may be stated again: Reasonable code quality is expected. You are programmers – programming should be an art to you. The quality of your code will be vital for its reuse and maintenance.

Common reasons for rejection

Polling/busy waiting

What is polling and what is not is a hard question. We here give some examples in pseudo code. Loops that reduce to something similar to the situation below (where the dots do not include any blocking wait) must be considered as polling.

while (e) { # POLLING!
   ...
   sleep(t); 
   ...
}

Using a blocking operation within a loop is not considered as polling.

while (e) { # NO POLLING!
   ...
   wait(o);
   ...
}

if it is not the case that something is regularly waking the process from its wait. Thus, the following example must be considered as an instance of polling:

obj o;

process a {   
  while (true) { 
    sleep(t);
    notify(o);
  }
}

process b {  # POLLING!
  while (e) {
    wait(o);
  }
}