The aim is to record "time of day" when a competitor starts, and "time of day" when they finish. Subtracting one from the other gives elapsed time, which for most competitions needs to be to 0.1 seconds, and for high level ones to 0.01 seconds. As this system is not likely to be used for high level competitions, I will aim for a reliable 0.1 second accuracy. I investigated options for synchronising two rpis but concluded that it would not be possible to do this with sufficient accuracy. Therefore I use one rpi which can receive trigger pulses from both the start and finish phone lines.
The first step was to create the analog electronics to run the phones and detect the button press. The phones run on a single pair of wires each, which provides power to the phone, carries the speech both ways, and detects the open circuit when the button is pressed. This last is converted into a pulse, stretched to avoid double-pulsing due to switch bounce, and fed to a gpio pin on the rpi. There are duplicate circuits for start and finish operation. Note that the switch diagram is out of step with the descriptions. It's now 4-position but only shows 3-positions.
Next was the requirement to detect the pulse and record the "time of day" when it occurred. The gpio softtware module allows the pins to be configured, e.g. whether to respond to a high or low state, or rising or falling edges. It does not allow for triggering an interrupt and calling user code when this occurs. The documentation I have found does not provide sufficient information to do this by accessing the hardware directly either, leaving me with the somewhat clunky approach of running some code from the tickerV interrupt, which occurs every 0.01 seconds, and checking the gpio registers each time to see whether a pin has changed state.
Naturally this has to be done in either C or Assembler. I don't have a C compiler, mainly because when I started programming ARM computers the compiler cost more than the computer. I have however written assembler on 6502, Z80 and VAX, the latter being 32-bit. Some of the 6502 assembler was interrupt code on the BBC, so it's not a totally new environment for me. Assembler it is then.
ARM assembler is interesting. Every instruction including its arguments is 32-bits. It should be obvious, and I rapidly discovered, that you cannot fit the opcode and a 32-bit address into 32-bits. This means that directly addressing arbitrary areas of memory cannot be done. This means using some other method, and the one I mainly used is to set a register to contain the base address of the memory block, and use offsets into the block from the register. Of course, you also cannot say "load register n with a 32-bit address", because that also requires fitting a 32-bit value into a 32-bit opcode. As I'm calling this code from BASIC this is easily solved by using the USR instruction, which loads registers from BASIC variables on entry, and returns data in them as well.
Testing code hooked into tickerV needs care too, as errors here generally crash the machine. I developed the code initially by calling it repeatedly from BASIC until I had eliminated errors from the part that did the work, then added the bits to allow it to be called from interrupt.
Now I had code which detected the pulses and recorded time stamps for them. The next step is to find out how accurate the rpi clock is over a long time period. The times of competitors during the event are also recorded using stopwatches as backup, and these backup times are periodically checked during the event against those recorded by the main method. It's important that these checks are within 1 second over a 2 to 3 minute run. Nothing better is required, because there will be human-induced differences between pressing the stopwatch button and the phone button, at each end, even if the same person presses both buttons. I recorded a start time and started a stopwatch and left it overnight. I was pleasantly surprised to find it was only a couple of seconds different in the morning.
This interrupt code stores up to 7 timestamps, which BASIC retrieves at its leisure. This means that if the computer happens to be doing something compute-intensive, it will not affect the timing. It may delay the display of information to the operator.
Each computer screen on the network displays the time from its internal clock. The time stamps for start are also displayed on the finishers screen in the same format. It's helpful therefore if these conform to the local actual time of day, and agree with each other. This means getting the time of day of one computer set accurately, and copying it to the others with less than 1 second difference - people can't detect a smaller difference when comparing two screens. We cannot rely on having an internet connection, so the current plan is to use an RTC clock hardware device on the timing computer, and the software already included in the slalom suite which sets each computer's clock from the server.
This is restricted to one person operation, because it has start and finish on the same screen. It would in theory be possible to use a touch screen to allow two people to run it, but to get the icons big enough to select without ambiguity, it would need at least a ten-inch screen, and they are expensive. The workload can be quite high handling start and finish, so this is likely to be used just at lowest division events, where entry numbers are low so a relaxed timetable can be used.
For two-person operation a different solution is used. The starter and finisher programs are on two different computers (one of which might be the one connected to the hardware). When a start or finish pulse is detected its timestamp is sent to the server, which stores it in a file. The server then sends it to either starter or finisher programs, depending on which event caused the pulse.
These programs can queue up to 5 timestamps, which could be useful if the operator is distracted, or paddlers finish close together. The operator selects a paddler from the list displayed, and if there is more than one timestamp, select a timestamp. A message is then sent to the server. The result is to add the paddler details to the timestamp already stored. The server then scans the timestamp file for a pair of timestamps, one finish and one start, with the same paddler details, calculates the elapsed time, and stores it for the paddler.
For convenience, and to give the operator reassurance about what is happening, the timestamps are displayed in time-of-day format. The finisher also shows the running time of the currently selected finisher, by using the start timestamp, and the computer's internal clock. This will be in error by the difference between the timing computer's clock and that of the clerk's computer. It is corrected when a finish time is received. These are displayed in the null process, every 0.1 seconds. With the server, timing monitor, starter and finisher all running on one rpi 3B+, it uses about 15% of the computers CPU capacity, so performance isn't going to be an issue. Realistically they won't all be on the same computer.
The backup times mentioned earlier are done by means of 4 synchronised stopwatches, two at start and two at finish. Before the event starts these are all started simultaneously. A facility has been added to store the timestamp of this in the server, and to display timestamps on screen relative to the stopwatches instead of time of day. This means that the stopwatches and timestamps can be compared directly while the event is running.
All this requires the ability to add and substract timestamps. System time is a 5-byte value, so doing this arithmetic in BASIC can be tricky. In February 2021 the high byte of the time will be incremented, and timestamp arithmetic across this transition needed special checking. In order to simplify the assembler code, tickerV interrupts are counted from zero when the software is started, and the system clock at this point is stored within the BASIC program. The timestamp therefore consists of a 5-byte system time, plus a 4-byte offset, and a flag to indicate whether it is a start or finish event. Normally therefore the 5-byte portion will not change. However if the timing program has to be restarted during the event, the start and finish stamps for paddlers on the water at the time will have different system parts of the timestamp, and this has to be allowed for.
All of the above therfore may help to explain several threads I have had operating on the ROOL Forums.