Sunday 21 January 2018

Controlling the CBR from a Texas Instruments TI-89 / TI-92 / Voyage 200

OK.  Slightly odd one this, but I'm writing it up here for three reasons:
  1. I've got a load of bits of paper on my desk at home with scribbles about it and I want to chuck them away, and
  2. I couldn't find this information anywhere on the web already, and
  3. I can't think of anywhere better to put it
I don't know if anyone else will be interested, but someone may get some use out of it.

Background


I have some old Texas Instruments calculators and a CBR 2 ultrasonic "Calculator-Based Ranger", which is designed for school classroom use to do experiments which measure and undertand distance/velocity/acceleration data at rapid intervals and then allow students to plot graphs and analyse the data on their calculators.

TI supply some software for these devices - EasyData on the TI-83/84 and a program called Ranger for the TI-89/92/Voyage 200 series.  The former is fine: easy to use and powerful.  However, the latter software I found particularly awkward to use and, seeing as it was just a program written in the TI BASIC on the calculator, which you can view and edit, I thought I might be able to do a better job of it, if only I could understand how it worked.

What's here is the result of me decoding the Ranger program and reverse engineering the protocol which the calculator uses to talk to the CBR 2.  This allowed me to write a much better program (in my opinion!) which I called "CBR Logger" — I'm quite happy to supply a copy of that to anyone that wants it.

To give you an idea about what that program, and the CBR can do, here are some screen shots from a TI-92 Plus showing the data captured from me bouncing a (soccer) football on the wood floor of my living room (processed in "Ball bounce" mode):

Logging setup dialog
Time/distance graph being traced
Time/velocity graph
Time/distance+velocity combined graph with menu

I must say, the hardest part about this wasn't reverse engineering the protocol so much as understanding the Ranger program: it's either been written to be as compact as possible and includes lots of weird hacks, or someone deliberately obscured it to stop people trying to understand it!

Note that I've got a CBR 2: I haven't got a CBR (original model), so I don't know if this applies to that too.  However,  I think it probably should, as the Ranger software claims to support both.  For brevity in these instructions, I'm just going to refer to both units as the "CBR", even though all my testing is with a CBR 2.

Basic operation


The CBR 2 connects to the calculator in one of two ways:
  • Via the standard TI calculator link cable — the 2.5mm stereo jack cable, which you use to connect two calculators together and transfer data and programs, or
  • On the TI-89 Titanium, you can use the USB B (CBR end) to USB C (calculator end) cable.
The end result is the same as the calculator hides these differences from programs written in TI BASIC.

To send data to the CBR, the "Send" command is used, which takes a list of numbers as a TI BASIC list (e.g. "Send {1,11,2,2}"}.  In the case of the CBR, the first one or two numbers specify the command number and the numbers following the parameters for that command.

To retrieve data from the CBR (either logged data, or status information about the CBR itself), the "Get" command is used.  This takes an argument which is the name of a variable to retrieve a list of numbers into.  What these numbers mean depends on the command that has been sent first.

The CBR can operate in two main modes:
  • Logging mode — the parameters for logging are set up by the calculator (interval between samples and number of samples required) and the CBR primed to sample.  When started, the CBR will log the sampled data points into its internal memory (up to 512 points' worth) and then stop.  The calculator can then retrieve the data from the internal memory of the CBR.  This method allows the CBR to be disconnected from the calculator during the experiment and reconnected, once the data has been logged, so it can be retrieved.
  • Real-Time mode — the CBR starts sampling and the calculator pulls down the data from it, as it is sampled.  The CBR doesn't record any of this information internally and so can sample data for as long as its batteries last.  The calculator can also process this data as it's captured, perhaps to draw a graph immediately, whilst the experiment is in progress.  However, the calculator cannot capture data particularly quickly, making it unsuitable for high speed events.  In addition, the calculator must obviously be connected to the CBR throughout the experiment.

Commands


The following table gives an overview of the commands that I've found (with my names for them):

NumberCommand
0Reset And Clear
1Stop or Set Up Sampling
3Start Sampling
5Select Logged Data
6Shutdown or Smooth Logged Data
7Get CBR Status

The exact meaning of these commands and the arguments they take are described below.

Of course, there may be more commands or options to what I've found, but I am, of course, reverse engineering what's in the Ranger program, and that may not use all the features.

Command 0 — Reset And Clear


The first command is {0} - it takes no parameters and resets the CBR, clearing any logged data from the internal memory of the CBR.

If invalid commands or parameters to commands are sent, sometimes the CBR gets in an error state and refuses to accept any commands until command 0 is sent to reset it.  When it's in this state, it usually flashes the LED on the front red, whenever a command is sent to it.


Command 1,0 — Stop


This command takes no parameters and just stops the CBR if it is logging in real-time mode (following command 3).


Command 1,11 — Set Up Sampling


This command is tightly integrated with command 3 (Sample).  It's unclear why the parameters specified here are separated from those with command 3, but that's the way it is!

The command is in the form:

{1,11,mode,sets}

The mode parameter is a bitwise field and contains and takes a value which is calculated as:

2 + (0 = log in CBR, or 4 = real time) + (0 = metres, 1 = ft)

The difference between logging and real-time modes is described above.

Note that the CBR will actually log in either meters or feet: it's not the software on the calculator which handles conversion between the different units (although it obviously could).

The sets parameter controls which data sets are returned in the cycle of retrieving with Get (see Getting Data, below) and is one of three values: 0 (distance only), 1 (distance and velocity) or 2 (distance, velocity and acceleration).  Choosing a mode which logs less information (e.g. 0 - distance only) doesn't free up any storage for more data points, so there isn't any particular benefit in limiting this, that I've found.  Also, even if a set is not selected here, command 5 can still be used to select the velocity and acceleration information (see below).

The sets parameter is ignored when logging in real time mode: it always returns all three measurements and time and can be omitted.

Command 3 — Start Sampling


This command follows on from 1,11 (Set Up Sampling - which you must send first, although you can send subsequent command 3s, to take another sample).  It takes quite a few parameters:

{3,interval,#samples,trigger,0,0,0,0,timing,smoothing}

The interval is the time in seconds between samples - e.g. 0.1 for a tenth of a second.  The minimum value appears to be 0.005 (1/200th of a second).

The #samples is the total number of samples to take.  The total length of the experiment will, thus, be interval * #samples seconds.  This value cannot exceed 512, which is presumably limited by the internal memory for logged data in the CBR.

To sample continuously, in real time mode, the value -1 (minus one) is specified.

Note that the value here must fit with that specified to command 1,11 — i.e. if real time mode is set there (mode +4), this value must be -1; if logging mode is set there, this value must be a positive integer in the range 1-512.

Trigger controls how sampling begins: 0 = immediately, 1 = when the TRIGGER button on the CBR itself is pressed and 7 = after 10 seconds.  The 10 second countdown timer is handled by the CBR itself: the LED on the CBR will flash green, each second in countdown, blinking rapidly in the last second before sampling begins.

The next four parameters must be zero.  I don't know if they could do anything useful!

The timing parameter controls how timings are returned in the logged data: 0 = do not return timing data, 1 = return absolute times (since the start of sampling), 2 = return relative times (time between a data point and the last, essentially the same as interval).  When running in real time mode, this parameter must be 0 and all times will be returned relative to the last sample (see the example).

The final parameter is smoothing.  This specifies the level of smoothing the CBR will perform on the data being returned, to reduce noise.  It ranges from 0 (= none), through 1 (= low), 2 (= medium) and 3 (= high) — these are the terms used in the Ranger program.  It's unclear exactly what the algorithm is for smoothing: it may refer to the number of adjacent points the value is smoothed over.  When in real time mode, this parameter must be 7.

Following this command, data is obtained with calls to Get (see below).

Command 5 — Select Logged Data


This command is used to select what part of the data logged in the CBR from a previous sampling run is to be retrieved with subsequent Gets to retrieve the data.  It takes the form:

{5,11,set,start,end}

The set parameter chooses the set of data to be retrieved next.  Data retrieved cycles between {distance, velocity, acceleration, time} (as enabled by commands 1 and 3) and this shifts that cycle to the specified data set: 0 (= distance), 1 (= velocity) or 2 (= acceleration).  See "Getting Data" below.

This command can be used to retrieve data which was not included in command 1 (e..g if command 1 specified only distance and velocity to be logged, command 5 can still be used to select acceleration data).

The start and end parameters allow a range of data points to be specified to retrieve partial data.  The start value is 1 for the first point and can range up to the total number of logged points; the end value specifies the last point to be retrieved and can be 0 to include all values from the start value to the last, so start=1, end=0 will include all logged points.

Once used, subsequently retrieved data will be restricted to the range specified, until it is reset.

This command obviously makes no sense following a real time experiment, since nothing is logged by the CBR, in that mode.

Command 6,2 — Shutdown


The Ranger program sends command {6,2} when it exits.  I assume this is some sort of "shutdown" command that puts the CBR into a low power state (which it may well do automatically, if you don't send anything to it for a few minutes).  The CBR seems to take longer to respond to the next command, after sending this, but that could be anecdotal!

Regardless, this command does not erase any logged data held in the CBR (which I assume will stay there until the batteries run out, or it's explicitly cleared with command 0).

Command 6,6 — Smooth Logged Data


This command smoothes the logged data already held in the CBR (following a non-real time sampling with command 3).  It takes a single parameter in the form:

{6,6,smoothing}

Smoothing is the level of smoothing to apply to the data and values match the smoothing parameter in command 3 (0 to 3: none-low-medium-high).

After applying this command, the data retrieved from the CBR will be appropriately smoothed (however, that algorithm works!).

The command can be called again with a different value and the smoothing reapplied (or cancelled) from the originally-logged data: smoothing only affects the data returned to the calculator, not what is stored in the CBR.

Command 7 — Get Status


This command takes no parameters but a subsequent call to Get will return a 17-element list, describing the current status of the CBR:

ElementDescription
1Always 11.210
2Last error code: 0 = no error
3Battery status: 0 = OK, 1 = low, 2 = replace
4
5Interval for sampling in seconds (as specified in command 3)
6
7Mode (as specified in command 1)
8Sets (as specified in command 1)
9Smoothing (as specified in command 3)
10#samples (as specified in command 3); -1 if sampling in real time; rather oddly returns 99 if the CBR is cleared with command 0
11Timing (as specified in command 3)
12
13
14Status: 1 = not set up / initialised, 2 = armed (waiting for TRIGGER button or in 10s countdown), 3 = sampling in progress, 4 = done (logged data available)
15Start (as specified in command 5)
16End (as specified in command 5)
17

The rows with no description I don't know what they mean!

The 11 in element 1 and its recurrence in various commands make me think the CBR may be something like "device type 11" and possibly different values would be used to select different parts of the CBL (Calculator-Based Laboratory) equipment set, which I believe the CBR can be connected to, as well as directly to the calculator.

After using this command, subsequent Gets will revert to returning data from the CBR.

Error codes


There are probably lots of these, but I did start making a list of some, by deliberately sending invalid parameters to the CBR and then checking the "last error code" in the status list.  Here are some I found:

CodeMeaning/cause
12Invalid second parameter to command 1 (not 0 or 11)
32Invalid interval (in command 3)
33#samples out of range (more than 512)
34Invalid mode (in command 1) or trigger (in command 3)
39Timing parameter invalid (in command 3)

Getting Data


Once data has been logged, or real time sampling started, no specified command is required to retrieve data from the CBR, although some commands (such command 5) can be used to affect what is returned.  A call to Get will just return a list of the data.

The way data is returned is different based on whether the CBR is operating in logging mode or real time mode.

Logging Mode Data


In logging mode, calls to Get will cycle between the different types of data set to be returned in command 1, followed by the timing of the data points, if enabled in command 3:

# in cycleData
1Distance
2Velocity (if command 1, set >= 1)
3Acceleration (if command 1, set >= 2
4Timing (if command 3, timing > 0): absolute (timing = 1) or relative (timing = 2)

Get will return a list with the length of the number of data points logged: first to last.

There is no way to tell at which point you are in the cycle, although command 5 can be used to select a particular set of data, although not the timing information.

Real Time Mode Data


In real time mode, Get always returns a 4 element list, containing the distance, velocity, acceleration and relative time (since the last data point retrieved).  Since the CBR returns the relative time, the calculator doesn't have to handle any delays or timing on its part: if the CBR samples multiple points in that time, it does some sort of averaging over the period between Gets.

If no data is available because the calculator is trying to retrieve data before the CBR has sampled any, the Get call will wait until some is available and the relative time will be that of the timing interval.

Obviously, how quickly you can sample the CBR depends on your program, but I managed to pull data from it and plot points on the screen in real time at about 0.1 to 0.15s intervals on a TI-92 Plus (which is slightly faster than an original TI-92 and TI-89).  For shorter intervals, you're best using logging mode.

Examples


You can easily control the CBR by manually entering commands on the Home screen of the calculator.  I'll give you a couple of examples here, just to show how everything fits together.

Logging mode example


Start by initialising the CBR:

Send {0}

Then set it up for logging mode (+ 0) in metres (+ 0) [+ 2  = 2], returning distance/velocity/acceleration [= 2]:

Send {1,11,2,2}

Start sampling at 0.1s intervals, capturing 30 points (for a total of 3s), beginning the capture with the CBR's TRIGGER button [= 1], returning absolute time information [= 1] with medium smoothing [2]:

Send {3,.1,30,1,0,0,0,0,1,2}

Before pressing TRIGGER, check the status of the CBR and print it:

Send {7}:Get s:s[14]

... this should print 2, indicating the CBR is "armed", ready for collection.

Enter the command again but don't push ENTER yet.  Push the TRIGGER button and then press ENTER immediately (or at least within 3 seconds) — the CBR should click 30 times as it samples.  This time, the value 3 should be printed, indicating the CBR is currently sampling.

Once sampling is complete, you can run the command again and you should get 4, indicating sampling is complete and logged data available for retrieval.

There is no need to check the status of the CBR whilst doing this: I'm just showing this for completeness.

Following the above, the next call to Get will return distance data:

Get d:d

... the displayed value of d will be a 30 element list, giving the distance at each of the 30 timed data points measured, in metres.

The next calls to Get will return the velocity, acceleration and absolute time values:

Get v:v
Get a:a
Get t:t

The last one should contain the numbers from 0.1 to 3, inclusive, giving the times of the measured points.  In practice, I often get back slightly different values, such as 2.99999, which I assume is rounding in the CBR or calculator.

Real time mode example


Start by initialising the CBR:

Send {0}

Then set it up for real time mode (+ 4) in feet (+ 1) [+ 2 = 7]:

Send {1,11,7}

Now start sampling at 0.2s intervals, continuously [= -1], immediately [= 0] — the CBR should being clicking:

Send {3,0.2,-1,0,0,0,0,0,0,7}

You can now use Get to retrieve samples when you want:

Get i:i

The value returned will be the current distance in feet, velocity in ft/s, acceleration in ft/s^2 and the time since the last point retrieved with Get.  If you repeat the command quickly, the final value will shorter, since you're sampling more frequently; if you leave things a few seconds before repeating it, the interval will be longer.

When you've finished getting all the data you want, stop sampling with:

Send {1,0}

The CBR should now stop clicking.