import struct


def decode_timestamp(ts_bytes):
    """
    Decode timestamp tuple from values saved in FITS file

    The timestamp is originally encoded to bytes as a series of
    32bit (4 bytes) unsigned integers in little endian byte format.

    Added to this is a pair of chars (1 byte) for the number of satellites
    tracked and a sync status.

    However, this is then stored as fake pixels in a FITS file, which
    performs some mangling of the data, since FITS assumes 16bit (2 byte)
    integers, and has no way to store unsigned integers. The following
    mangling occurs:

    - decode the timestamp byte string as two 16bit (2 bytes) little-endian unsigned integers;
    - subtract 32768 from each integer;
    - encode these integers as two 16bit signed integers in BIG ENDIAN format;
    - save to file as fits data.

    This routine reverses this process to recover the original timestamp tuple. We have to
    take some care because of all the endian-swapping going on. For example, the number 27
    starts off as \x1b\x00\x00\x00, which is interpreted by the FITS save process as (27, 0).
    If we ignore the signing issue for clarity, then (27, 0) encoded in big endian format is
    \x00\x1b, \x00\x00 so we've swapped the byte pairs around.

    The steps taken by this routine are:

    - decode timestamp string as big endian 16bit integers
    - add 32768 to each value
    - encode these values as little endian 16bit unsigned integers
    - re-interpret the new byte string as 32bit, little-endian unsigned integers

    The status bytes are handled slightly differently: after the re-encoding to little endian
    16 bit uints, they are decoded as chars, and the last two chars discarded.

    Parameters
    ----------
    ts_bytes: bytes
        a Python bytes object which contains the timestamp bytes as written in the
        FITS file

    Returns
    --------
    timestamp : tuple
        a tuple containing the (frameCount, timeStampCount,
                                years, day_of_year, hours, mins,
                                seconds, nanoseconds) values.
    """
    buf = struct.pack('<' + 'H'*18, *(val + 32768 for val in struct.unpack('>'+'h'*18, ts_bytes)))
    return struct.unpack('<' + 'I'*8, buf[:-4]) + struct.unpack('bb', buf[-4:-2])