def test_encode_decode():
    anc = AncillaryData()
    anc.FirstBinRange = 1.0  # Blank.  Depth to the first bin in meters.
    anc.BinSize = 3.0  # Size of a bin in meters.
    anc.FirstPingTime = 1.2  # First Ping Time in seconds.
    anc.LastPingTime = 2.3  # Last Ping Time in seconds.  (If averaging pings, this will be the last ping)
    anc.Heading = 23.5  # Heading in degrees.
    anc.Pitch = 13.6  # Pitch in degrees.
    anc.Roll = 11.25  # Roll in degrees.
    anc.WaterTemp = 25.3  # Water Temperature in fahrenheit
    anc.SystemTemp = 54.6  # System Temperature in fahrenheit
    anc.Salinity = 35.0  # Water Salinity set by the user in PPT
    anc.Pressure = 23.78  # Pressure from pressure sensor in Pascals
    anc.TransducerDepth = 45.69  # Transducer Depth, used by Pressure sensor in meters
    anc.SpeedOfSound = 1400.23  # Speed of Sound in m/s.
    anc.RawMagFieldStrength = 3.0  # Raw magnetic field strength
    anc.RawMagFieldStrength2 = 4.0  # Raw magnetic field strength
    anc.RawMagFieldStrength3 = 5.0  # Raw magnetic field strength
    anc.PitchGravityVector = 4.0  # Pitch Gravity Vector
    anc.RollGravityVector = 5.0  # Roll Gravity Vector
    anc.VerticalGravityVector = 6.0  # Vertical Gravity Vector

    # Populate data

    result = anc.encode()  # Encode

    anc1 = AncillaryData()
    anc1.decode(bytearray(result))  # Decode

    assert anc.FirstBinRange == pytest.approx(anc1.FirstBinRange, 0.1)
    assert anc.BinSize == pytest.approx(anc1.BinSize, 0.1)
    assert anc.FirstPingTime == pytest.approx(anc1.FirstPingTime, 0.1)
    assert anc.LastPingTime == pytest.approx(anc1.LastPingTime, 0.1)
    assert anc.Heading == pytest.approx(anc1.Heading, 0.1)
    assert anc.Pitch == pytest.approx(anc1.Pitch, 0.1)
    assert anc.Roll == pytest.approx(anc1.Roll, 0.1)
    assert anc.WaterTemp == pytest.approx(anc1.WaterTemp, 0.1)
    assert anc.SystemTemp == pytest.approx(anc1.SystemTemp, 0.1)
    assert anc.Salinity == pytest.approx(anc1.Salinity, 0.1)
    assert anc.Pressure == pytest.approx(anc1.Pressure, 0.1)
    assert anc.TransducerDepth == pytest.approx(anc1.TransducerDepth, 0.1)
    assert anc.SpeedOfSound == pytest.approx(anc1.SpeedOfSound, 0.1)
    assert anc.RawMagFieldStrength == pytest.approx(anc1.RawMagFieldStrength,
                                                    0.1)
    assert anc.RawMagFieldStrength2 == pytest.approx(anc1.RawMagFieldStrength2,
                                                     0.1)
    assert anc.RawMagFieldStrength3 == pytest.approx(anc1.RawMagFieldStrength3,
                                                     0.1)
    assert anc.PitchGravityVector == pytest.approx(anc1.PitchGravityVector,
                                                   0.1)
    assert anc.RollGravityVector == pytest.approx(anc1.RollGravityVector, 0.1)
    assert anc.VerticalGravityVector == pytest.approx(
        anc1.VerticalGravityVector, 0.1)
    def decode_data_sets(ens):
        """
        Decode the datasets in the ensemble.

        Use verify_ens_data if you are using this
        as a static method to verify the data is correct.
        :param ens: Ensemble data.  Decode the dataset.
        :return: Return the decoded ensemble.
        """
        #print(ens)
        packetPointer = Ensemble().HeaderSize
        type = 0
        numElements = 0
        elementMultiplier = 0
        imag = 0
        nameLen = 0
        name = ""
        dataSetSize = 0
        ens_len = len(ens)

        # Create the ensemble
        ensemble = Ensemble()

        # Add the raw data to the ensemble
        #ensemble.AddRawData(ens)

        try:

            # Decode the ensemble datasets
            for x in range(Ensemble().MaxNumDataSets):
                # Check if we are at the end of the payload
                if packetPointer >= ens_len - Ensemble.ChecksumSize - Ensemble.HeaderSize:
                    break

                try:
                    # Get the dataset info
                    ds_type = Ensemble.GetInt32(packetPointer + (Ensemble.BytesInInt32 * 0), Ensemble().BytesInInt32, ens)
                    num_elements = Ensemble.GetInt32(packetPointer + (Ensemble.BytesInInt32 * 1), Ensemble().BytesInInt32, ens)
                    element_multiplier = Ensemble.GetInt32(packetPointer + (Ensemble.BytesInInt32 * 2), Ensemble().BytesInInt32, ens)
                    image = Ensemble.GetInt32(packetPointer + (Ensemble.BytesInInt32 * 3), Ensemble().BytesInInt32, ens)
                    name_len = Ensemble.GetInt32(packetPointer + (Ensemble.BytesInInt32 * 4), Ensemble().BytesInInt32, ens)
                    name = str(ens[packetPointer+(Ensemble.BytesInInt32 * 5):packetPointer+(Ensemble.BytesInInt32 * 5)+8], 'UTF-8')
                except Exception as e:
                    logging.warning("Bad Ensemble header" + str(e))
                    break

                # Calculate the dataset size
                data_set_size = Ensemble.GetDataSetSize(ds_type, name_len, num_elements, element_multiplier)

                # Beam Velocity
                if "E000001" in name:
                    logging.debug(name)
                    bv = BeamVelocity(num_elements, element_multiplier)
                    bv.decode(ens[packetPointer:packetPointer+data_set_size])
                    ensemble.AddBeamVelocity(bv)

                # Instrument Velocity
                if "E000002" in name:
                    logging.debug(name)
                    iv = InstrumentVelocity(num_elements, element_multiplier)
                    iv.decode(ens[packetPointer:packetPointer+data_set_size])
                    ensemble.AddInstrumentVelocity(iv)

                # Earth Velocity
                if "E000003" in name:
                    logging.debug(name)
                    ev = EarthVelocity(num_elements, element_multiplier)
                    ev.decode(ens[packetPointer:packetPointer+data_set_size])
                    ensemble.AddEarthVelocity(ev)

                # Amplitude
                if "E000004" in name:
                    logging.debug(name)
                    amp = Amplitude(num_elements, element_multiplier)
                    amp.decode(ens[packetPointer:packetPointer+data_set_size])
                    ensemble.AddAmplitude(amp)

                # Correlation
                if "E000005" in name:
                    logging.debug(name)
                    corr = Correlation(num_elements, element_multiplier)
                    corr.decode(ens[packetPointer:packetPointer+data_set_size])
                    ensemble.AddCorrelation(corr)

                # Good Beam
                if "E000006" in name:
                    logging.debug(name)
                    gb = GoodBeam(num_elements, element_multiplier)
                    gb.decode(ens[packetPointer:packetPointer+data_set_size])
                    ensemble.AddGoodBeam(gb)

                # Good Earth
                if "E000007" in name:
                    logging.debug(name)
                    ge = GoodEarth(num_elements, element_multiplier)
                    ge.decode(ens[packetPointer:packetPointer+data_set_size])
                    ensemble.AddGoodEarth(ge)

                # Ensemble Data
                if "E000008" in name:
                    logging.debug(name)
                    ed = EnsembleData(num_elements, element_multiplier)
                    ed.decode(ens[packetPointer:packetPointer+data_set_size])
                    ensemble.AddEnsembleData(ed)

                # Ancillary Data
                if "E000009" in name:
                    logging.debug(name)
                    ad = AncillaryData(num_elements, element_multiplier)
                    ad.decode(ens[packetPointer:packetPointer+data_set_size])
                    ensemble.AddAncillaryData(ad)

                # Bottom Track
                if "E000010" in name:
                    logging.debug(name)
                    bt = BottomTrack(num_elements, element_multiplier)
                    bt.decode(ens[packetPointer:packetPointer + data_set_size])
                    ensemble.AddBottomTrack(bt)

                # NMEA data
                if "E000011" in name:
                    logging.debug(name)
                    nd = NmeaData(num_elements, element_multiplier)
                    nd.decode(ens[packetPointer:packetPointer + data_set_size])
                    ensemble.AddNmeaData(nd)

                # System Setup
                if "E000014" in name:
                    logging.debug(name)
                    ss = SystemSetup(num_elements, element_multiplier)
                    ss.decode(ens[packetPointer:packetPointer + data_set_size])
                    ensemble.AddSystemSetup(ss)

                # Range Tracking
                if "E000015" in name:
                    logging.debug(name)
                    rt = RangeTracking(num_elements, element_multiplier)
                    rt.decode(ens[packetPointer:packetPointer + data_set_size])
                    ensemble.AddRangeTracking(rt)

                # Move to the next dataset
                packetPointer += data_set_size

        except Exception as e:
            logging.warning("Error decoding the ensemble.  " + str(e))
            return None

        return ensemble