Protocol and Data Structure of Uwatec Aladin Dive Computers


Hardware and Protocol

Feeble signal comes from Aladin is amplified to gain the RS232C voltage level by an OP amp in electronics of the DIY interface (or the Uwatec interface --- MSDOS version). Since the OP amp needs +Vcc and -Vss, PC must supply both. In order to do this, two flags in the register of UART should be changed to

         DTR = 1   negate ('space' in RS232C terminology)
and
         RTS = 0   assert ('mark').
(N.B. DTR and RTS are negative logic.)

Aladin sends 2050 bytes of data to PC at

         19200 baud, 8 bits, No parity and 1 stopbit,
when either of the following condition is met:
  1. Just before "logbook mode" turned into "1st logbook mode", after moist fingers touch to the two contacts of Aladin.
  2. SOS mode (every one minute).
Thus, from PC side we cannot initiate the data transfer. When Aladin is not sending valid data (or Aladin is not connected), RD line of RS232C is read as garbage from PC side. Then, how can we do to receive valid data? For this purpose, before sending the 2046 bytes of dive data, Aladin sends a consecutive four characters sequence
                       UUU\0
(three ASCII character U's followed by one null character). Now it is easy to distinguish garbage and data; the sequence "UUU\0" marks the starting point.

After the sequence "UUU\0", Aladin always sends 2046 bytes of dive data. At PC side, each byte (8 bits) in the received data is in reversed bit order, that is, if

  received bit order from Aladin:  b_0 b_1 b_2 b_3 b_4 b_5 b_6 b_7
then
  ordinary bit order of PC:        b_7 b_6 b_5 b_4 b_3 b_2 b_1 b_0.
We must rearrange every byte before proceeding further data processing.

There are last two bytes of "check sum" for error checking; 2045th byte and 2046th byte. Algorithm for calculating the check sum will be explained later.


Data Structure of Received Data

The 2046 bytes from Aladin are divided into four parts:

   Address        Description
==============================================
    0x000
      |     (1) Depth Profile ring buffer
    0x5ff
----------------------------------------------
    0x600
      |     (2) Logbook ring buffer
    0x7bb
----------------------------------------------
    0x7bc
      |     (3) Settings Section
    0x7ef
----------------------------------------------
    0x7f0
      |     (4) Current Status
    0x7fd
Explanation for each part follows.

(1) Depth Profile ring buffer

The beginning of the oldest profile chunk can be found as follows: Start from the address stored in "end of profile ring buffer" (0x7f6--0x7f7) of the part (4), and search higher address direction for a byte 0xff. The mark 0xff designates the oldest beginning.

A profile data block begins with the byte 0xff, and end with just before another 0xff or the address of "end of profile ring buffer." The layout of a profile is:

Offset      Description
====================================================
  0         Constant 0xff (marks the beginning)
  1--22     Information for decompression  
            Note 1: Aladin Nitrox (not O2) has extra two bytes.  This is 
                  turned out to be the following memory map shifts by two bytes.
            Note 2: Aladin O2 has extra three bytes.  This is turned out 
                  to be the following memory map shifts by three bytes.
            1:      Ambient temperature when this dive starts (at 1.25m)
                    [1] / 4 degrees (Celsius).
                    Note: This value is not surface temperature nor
                    air temperature.  The measurement is done when
                    this dive starts, so it is not reached to stable state.
            2--3:   Tissue 1  ([3]*256 + [2])     kidney
            4--5:   Tissue 2  ([5]*256 + [4])     stomach, bowels, liver, central nervous system
            6--7:   Tissue 3  ([7]*256 + [6])     central nervous system, liver, stomach, bowels
            8--9:   Tissue 4  ([9]*256 + [8])     skin
            10--11: Tissue 5  ([11]*256 + [10])   skin, muscles, heart
            12--13: Tissue 6  ([13]*256 + [12])   muscles
            14--15: Tissue 7  ([15]*256 + [14])   muscles, joints, bones, fat
            16--17: Tissue 8  ([17]*256 + [16])   fat, joints, bones, rest
            18-- higher nibble of 19:
                    Microbubble danger in the arterial circulation
                       ([19] & 0xf0)*16 + [18]
                    0x000 - 0x010: Level 0
                    0x011 - 0x080: Level 1
                    0x081 - 0x100: Level 2
                    0x101 - 0x280: Level 3
                    0x281 - 0x480: Level 4
                    0x481 - 0x700: Level 5
                    0x701 - 0xa00: Level 6
                    0xa01 - 0xfff: Level 7
            lower nibble of 19 --20:
                    Intrapulmonary right-left shunt: Micro bubbles in the venous
                    circulation migrate to the lungs, where they collect in the
                    capillaries and obstruct the exchange of gas, and this
                    effect is termed.
                       ([19] & 0x0f)*256 + [20]
            21-- higher nibble of 22:
                    Estimated skin cool at dive start (([22] & 0xf0)*16 + [21])/64
                          > 30.7 : Level 0
                         >= 28.0 : Level 1
                         >= 26.0 : Level 2
                         >= 24.0 : Level 3
                         >= 23.0 : Level 4
                         >= 22.0 : Level 5
                         >= 21.0 : Level 6
                          < 21.0 : Level 7
            lower nibble of 22: Always zero
           (Begin Nitrox only
            23:     Two times of CNS O2 rest saturation percentage at dive
                    start.  Aladin shows this value in 5% units as
                        floor(([23] + 4) / 10) * 5,
                    where floor(x) means the maximum integer not exceeding
                    x.  For example if [23] = 56 (28 %) then Aladin shows it as
                    30 %.
                (Begin Aladin Nitrox (not O2) only    
                 24:     Upper nibble: Max ppO2 warning of this dive
                            0x0*: 1.20 (bar)
                            0x1*: 1.25 (bar)
                            0x2*: 1.30 (bar)
                            0x3*: 1.35 (bar)
                            ....
                            0x8*: 1.60 (bar)
                            ....                (ppO2 value should not be set
                                                 higher than 1.60 bar)
                            0xf*: 1.95 (bar)
                         Lower nibble: Nitrox O2 mix
                            0x*0: 21% O2
                            0x*1: 22% O2
                            0x*2: 24% O2
                            0x*3: 26% O2
                            ....
                            0x*f: 50% O2
                 End Nitrox (not O2) only)
                (Begin Aladin O2 only
                 24:    Nitrox O2 mix [24] %
                 25:    Upper nibble:
                           bit7: higher bit of Work load (vvO2 max) of this dive
                           bit6: lower bit
                                    3: very high (2.50 l/min O2)
                                    2: high      (2.25 l/min O2)
                                    1: medium    (2.00 l/min O2)
                                    0: low       (1.75 l/min O2)
                           bit5: higher bit of SCR sensitivity of this dive
                           bit4: lower bit
                                    3: sensitive       (1)
                                    2:     |           (0)
                                    1:     |           (-1)
                                    0: insensitive     (-2)
                        Lower nibble: Max pp02 warning of this dive
                            0x*0: 1.20 (bar) 
                            0x*1: 1.25 (bar)
                            0x*2: 1.30 (bar)
                            0x*3: 1.35 (bar)
                            ....
                            0x*8: 1.60 (bar)
                            ....                (ppO2 value should not be set
                                                 higher than 1.60 bar)
                            0x*f: 1.95 (bar)
                 End O2 only)
            End Nitrox only)
  23--      Body of depth profile; 
            a word (16 bits) data for depth + warnings in every 20 seconds,
            a byte (8 bits) data for decompression in every one minute.

            (*)
            23--24  upper 10bits --- depth at 0:00:20 (hour:min:sec)
                    lower  6bits --- warnings at 0:00:20
            25--26  upper 10bits --- depth at 0:00:40
                    lower  6bits --- warnings at 0:00:40
            27--28  upper 10bits --- depth at 0:01:00
                    lower  6bits --- warnings at 0:01:00
            29      decompression information at 0:01:00
            (Aladin O2 has extra one byte, which represents 02 mix %, here)
            (repeat from above (*) to here as many times)

            A depth is stored as [upper 10bits] * 10 / 64 (m).
            For example, the depth at 0:00:20 can be calculated as
                  (([23] * 256 + [24]) >> 6) * 10 / 64 (m).
            Each bit of warning (lower 6bits) is 
              bit 5: transmit error of air pressure (always 1 unless Air series),
              bit 4: work too hard  (Air series only),
              bit 3: ceiling violation of deco stop,
              bit 2: ascent too fast,
              bit 1: remaining bottom time too short; 5 min to reserved bar
                     [0x7de] (default: 40 bar).  (Air series only),
              bit 0: deco stop.

            A decompression information of every minute is:
              Level of physical effort (min 0 -- max 7)
              ("Air" computer estimates it from air consumption; Uwatec applied
                this estimation procedure for the patent.  Other computer sets
                it to Level one in underwater and to zero when surfacing.)
                  bit 6: higher bit
                  bit 5:    |
                  bit 4: lower bit
              Estimated skin cooling
                  bit 7: cold level decrement by one
                  bit 3: cold level increment by one
              Level of micro bubble danger in the arterial circulation
              (min 0 -- max 7; if this value is not less than 2 then Aladin 
              enters in "Atn" mode)
                  bit 2: higher bit
                  bit 1:    |
                  bit 0: lower bit
Remark: If a dive is too long for the ring buffer, then the data will be dropped except for first part filling the buffer (i.e., first about 216 minutes part only remains).

(2) Logbook ring buffer

A logbook consists of a 12 bytes block. The position of the newest logbook is stored in "offset for the newest logbook data" (0x7f4) of part (4). The 12 bytes are:

Offset        Description
=======================================
0             bit7: high place diving flag:  higher bit
              bit6:                          lower bit
              bit5: SOS mode
              bit4: work too hard (Air only)
              bit3: decompression violation
              bit2: figure of hundreds of bottom time
              bit1: repeated diving
              bit0: ascent warning too long
         Remark:  high place diving flag (4 levels) represents
               (0)    0 m ---  900 m   (0 ft --- 3000 ft)
                                       ambient pressure above 0.921875 bar
               (1)  900 m --- 1750 m   (3000 ft --- 5700 ft) 
                                       ambient pressure above 0.828125 bar
               (2) 1750 m --- 2700 m   (5700 ft --- 8800 ft)
                                       ambient pressure above 0.73828125 bar
               (3) 2700 m --- 4000 m   (8800 ft --- 13300 ft)
                                       ambient pressure below 0.62109375 bar
1        Bottom time (stored in binary coded decimal (BCD)).
         Remark: The figure of the number of hundreds (0 or 1) is stored
         in the previous byte.  If a divetime exceeds 200 minutes, then
         divetime will be reset to 0 (e.g. divetime = 231 then stored-divetime
         = 31).
2--3     Maximum depth (([2] * 256 + [3])>>6 ) * 10 / 64 (m)
         Note: The lower 6 bits in [3] must be garbage, since
         Aladin seems to be using a 10 bits (not 16 bits!) A/D converter 
         LSI located outside of the CPU.  DataTrak and ROM program of Aladin, 
         however, consider these garbage bits into account and adopt the 
         formula:
         Maximum depth ([2] * 256 + [3]) * 10 / 4096 (m)
         Using this formula results in 0 to 0.2m over estimate of max depth,
         but I think discrepancies are very small :) (See also "Paladin FAQ" Q9).
4--5     Surface time in BCD (hours in [4] and minutes in [5])
         (Note: The value is garbage unless repeated dive).
6        Total air consumption (bar) (always zero unless Air series).
         Note: If type of Aladin is Aladin Air ([0x7bc] == 0x1c) then
         total air consumption is in 20psi unit: [6] * 20 [psi].
7--10    Entry time (the value is from 00:00 1 Jan, 1994 GMT) in unit of 
         0.5 seconds
         = [7] * 2^24 + [8] * 2^16 + [9] * 2^8 + [10].
11       Water temperature [11] / 4 degrees (Celsius).

(3) Settings Section

0x7bc         Type of Aladin:
                    
                             O2  Nitrox Air  Name
              [0x7bc] = 0x40 no  no     yes  Mares Genius
                        0x34 no  no     yes  Aladin Air X
                        0x44 no  no     yes  Aladin Air X
                        0xa4 yes yes    yes  Aladin Air X O2
                        0xf4 no  yes    yes  Aladin Air X Nitrox
                        0x48 no  no     yes  Spiro Monitor 3 Air
                        0x1c no  no     yes  Aladin Air
                        0x1d no  no     no   Spiro Monitor 2 Plus
                        0x3d no  no     no   Spiro Monitor 2 Plus
                        0x1e no  no     no   Aladin Sport
                        0x3e no  no     no   Aladin Sport
                        0x1f no  no     no   Aladin Pro 
                        0x3f no  no     no   Aladin Pro
                        0xff no  yes    no   Aladin Pro Nitrox
                        0x1b no  no     no   AIRE (Aladin Pro)

Note 1: In year 2000, Uwatec renamed their products as follows (but
the type codes shown above were not changed at all):
    New name            Old name
  Aladin Pro Ultra    Aladin Pro Nitrox
  Aladin Air Twin     Aladin Air
  Aladin Air Z O2     Aladin Air X O2
  Aladin Air Z Nitrox Aladin Air X Nitrox
  Aladin Air Z        Aladin Air X
  Aladin Sport Plus   Aladin Sport
And computers of US divers Monitor series are OEMs of Spiro.

Note 2: All Nitroxen (except O2) have ([0x7bc] & 0xf0) == 0xf0.
        The O2 has ([0x7bc] & 0xf0) == 0xa0.
        All Airs have ([0x7bc] & 0x0f) % 4 == 0.

Note 3: 0x1b is the type code for a dive computer that I got at a junk
        shop.  It seems to be compatible with Aladin Pro but the exact
        name is still unknown (since the name is not written on the casing).

0x7d2         bit7: higher bit of Work load (vvO2 max) (O2 only)
              bit6: lower bit
                    3: very high (2.50 l/min O2)
                    2: high      (2.25 l/min O2)
                    1: medium    (2.00 l/min O2)
                    0: low       (1.75 l/min O2)
              bit5: higher bit of SCR sensitivity (O2 only)
              bit4: lower bit
                    3: sensitive       (1)
                    2:     |           (0)
                    1:     |           (-1)
                    0: insensitive     (-2)
              bit3: always 0
              bit2: always 0
              bit1: Beep (0: Off, 1: On)
              bit0: Unit (0: Metric, 1: Imperial)

0x7d3         Upper nibble:
                  Premix reset after XX hours. (O2 only)
                  [0x7d3] = 0x0*:  1 hour
                            0x1*:  2 hours
                            0x2*:  3 hours
                            0x3*:  4 hours
                            0x4*:  5 hours
                            0x5*:  6 hours
                            0x6*:  8 hours
                            0x7*:  10 hours
                            0x8*:  12 hours
                            0x9*:  14 hours
                            0xa*:  16 hours
                            0xb*:  18 hours
                            0xc*:  24 hours
                            0xd*:  36 hours
                            0xe*:  48 hours
                            0xf*:  No reset
                  Remark: The value is 0 unless Aladin O2 computer.
              Lower nibble:
                  Maximum O2 partial pressure ppO2 (Nitrox only)
                  ([0x7d3] & 0x0f) * 0.05 + 1.2 (bar)
                  Remark: For non-Nitrox computers, always ([0x7d3] & 0x0f) = 6.

0x7de         Reserve (Air series only)
              [0x7de] (bar)
              Remark: For non-Air computers, always [0x7de] = 40.

0x7e1         Constant 0x64:  The value seems to be only used by DataTalk for DOS
              for compensating the full percentage (100 %) of battery, but
              not to be used by DataTalk for Windows.  Thus, we can consider
              the value as a constant, and safely ignore it.

0x7eb         Breath warning sensitivity (Air series only)
              Ranges are from 0x19 (insensitive) to 0x61 (sensitive).
              The following is correspondence between sensitivity values
              (say y) and the displayed values (say x) in DataTalk for Windows:

                          y    x
              [0x7eb] = 0x19: -12 
                        0x1b: -11 
                        0x1d: -10
                        0x1f: -9
                        0x21: -8
                        0x23: -7
                        0x25: -6
                        0x27: -5
                        0x2a: -4
                        0x2c: -3
                        0x2f: -2
                        0x31: -1
                        0x34: 0          (default: 0x33 or 0x34)
                        0x37: 1
                        0x3a: 2
                        0x3d: 3
                        0x41: 4
                        0x44: 5
                        0x48: 6
                        0x4c: 7
                        0x50: 8
                        0x54: 9
                        0x58: 10
                        0x5c: 11
                        0x61: 12
              Remark 1: Some Aladins (including some Nitroxen) have 
                      default value 0x01.
              Remark 2: The above table is calculated by the formula
                      y = rint((exp((x + 12) / 24) * k1 + k2) * 512),
                      where the constants k1 = 0.140625 / (exp(1) - 1)
                      and k2 = 0.048828125 - k1.

0x7ec         Unknown (Always 0x0b).
               
0x7ed--0x7ef  Serial number of the Aladin (does not match the 'external serial number' 
              written on the casing).
              = [0x7ed] * 2^16 + [0x7ee] * 2^8 + [0x7ef]
              Comment:  The 8 bits value X = [0x7ed] - [msb of 0x7ee] 
              seems to be related to the manufacture date of Aladin as
                 year = X / 6 + 1994;
                 beginning of two months period = (X % 6) * 2 + 1; 
Other bytes are all unknown.

(4) Current Status

0x7f0         Remaining battery
              = [0x7f0] * 100 / 256 (percent)
              Note: The above formula is used by DataTalk for DOS.
              It seems that ROM program of Aladin uses a similar but 
              different formula
                [0x7f0] * 99 / 255 (percent)
              for remaining battery.

0x7f1         lower nibble == 0     if battery is OK.
              lower nibble != 0     if battery is empty.

0x7f2--0x7f3  Total dive numbers this Aladin have experienced
              (initially every Aladin dives from 6 to 10 times at factory)
              = [0x7f2] * 256 + [0x7f3]

0x7f4         Offset for the newest logbook
              = (([0x7f4] + 36) % 37) * 12 + 0x600
              Note: The value of [0x7f4] is normally in range from 1 to 37.
              But some Aladin Pro only when number of total dives is equal
              to 37 the value becomes 0!!

0x7f5         Number of dive profiles in the ring buffer
              = [0x7f5]  (WARNING: Some older Aladin Pro has a bug
                          in the byte; they have an error value of
                          correct value plus one for this byte.)
        
0x7f6--0x7f7  End of profile ring buffer
              = (([0x7f6] + ([0x7f7] >> 1) * 256)) & 0x7ff
              Note1: Upper byte located in higher address and shifted 1 bit.
                    The lsb of upper byte is garbage (always zero). 
                    (Yes, very strange. :) But it may caused by the hardware
                    architecture of Aladin dive computer;  SRAM for storing
                    download data is located at I/O port of the CPU. )
              Note2: Higher 4 bits of [0x7f7] are garbage, too.

0x7f8--0x7fb  Current time of data acquisition (the time value is 
              from 00:00 1 Jan, 1994 GMT) in unit of 0.5 seconds
              = [0x7f8] * 2^24 + [0x7f9] * 2^16 + [0x7fa] * 2^8 + [0x7fb].
              Note: Since we cannot adjust the time of Aladin, this value
              has some discrepancy.

0x7fc--0x7fd  Check sum
              Check sum is calculated as follows:
              Sum up every byte in dive data except the last two bytes
              (from [0x0] to [0x7fb]) as an unsigned character.  Add it
              to 0x1fe.  Take modulo 65536 (= 2^16).  Then the result is
              unsigned 2 byte integer [0x7fd]*256 + [0x7fc].
              (Remark: 0x1fe = 0xaa + 0xaa + 0xaa + 0, and 0xaa is the
              bit reverse of ASCII 'U'.)