Retrieves data from eDNA history for a given tag.

    :param tag_name: fully-qualified (site.service.tag) eDNA tag
    :param start_time: must be in format mm/dd/yy hh:mm:ss
    :param end_time: must be in format mm/dd/yy hh:mm:ss
    :param period: specify the number of seconds for the pull interval
    :param mode: "raw", "snap", "avg", "interp", "max", "min"
        See eDNA documentation for more information.
    :param desc_as_label: use the tag description as the column name instead
        of the full tag
    :param label: supply a custom label to use as the DataFrame column name
    :param high_speed: if True, pull millisecond data
    :param utc: if True, use the integer time format instead of DateTime
    :return: a pandas DataFrame with timestamp, value, and status

def GetHist(tag_name, start_time, end_time, period=5, mode="raw",
            desc_as_label=False, label=None, high_speed=False, utc=False):
    """
    Retrieves data from eDNA history for a given tag.

    :param tag_name: fully-qualified (site.service.tag) eDNA tag
    :param start_time: must be in format mm/dd/yy hh:mm:ss
    :param end_time: must be in format mm/dd/yy hh:mm:ss
    :param period: specify the number of seconds for the pull interval
    :param mode: "raw", "snap", "avg", "interp", "max", "min"
        See eDNA documentation for more information.
    :param desc_as_label: use the tag description as the column name instead
        of the full tag
    :param label: supply a custom label to use as the DataFrame column name
    :param high_speed: if True, pull millisecond data
    :param utc: if True, use the integer time format instead of DateTime
    :return: a pandas DataFrame with timestamp, value, and status
    """
    # Check if the point even exists
    if not DoesIDExist(tag_name):
        warnings.warn("WARNING- " + tag_name + " does not exist or " +
            "connection was dropped. Try again if tag does exist.")
        return pd.DataFrame()

    # Define all required variables in the correct ctypes format
    szPoint = c_char_p(tag_name.encode('utf-8'))
    tStart = c_long(StringToUTCTime(start_time))
    tEnd = c_long(StringToUTCTime(end_time))
    tPeriod = c_long(period)
    pulKey = c_ulong(0)

    # Initialize the data pull using the specified pulKey, which is an
    # identifier that tells eDNA which data pull is occurring
    mode = mode.lower().strip()
    if not high_speed:
        if mode == "avg":
            nRet = dna_dll.DnaGetHistAvgUTC(szPoint, tStart, tEnd, tPeriod, byref(pulKey))
        if mode == "interp":
            nRet = dna_dll.DnaGetHistInterpUTC(szPoint, tStart, tEnd, tPeriod, byref(pulKey))
        if mode == "min":
            nRet = dna_dll.DnaGetHistMinUTC(szPoint, tStart, tEnd, tPeriod, byref(pulKey))
        if mode == "max":
            nRet = dna_dll.DnaGetHistMaxUTC(szPoint, tStart, tEnd, tPeriod, byref(pulKey))
        if mode == "snap":
            nRet = dna_dll.DnaGetHistSnapUTC(szPoint, tStart, tEnd, tPeriod, byref(pulKey))
        else:
            nRet = dna_dll.DnaGetHistRawUTC(szPoint, tStart, tEnd, byref(pulKey))
        time_, val, stat = _GetNextHistSmallUTC(pulKey, nRet)
    else:
        nStartMillis = c_ushort(0)
        nEndMillis = c_ushort(0)
        nRet = dna_dll.DnaGetHSHistRawUTC(szPoint, tStart, nStartMillis,
            tEnd, nEndMillis, byref(pulKey))
        time_, val, stat = _GetNextHSHistUTC(pulKey, nRet)

    # The history request must be cancelled to free up network resources
    dna_dll.DnaCancelHistRequest(pulKey)

    # To construct the pandas DataFrame, the tag name will be used as the
    # column name, and the index (which is in the strange eDNA format) must be
    # converted to an actual DateTime
    d = {tag_name + ' Status': stat, tag_name: val}
    df = pd.DataFrame(data=d, index=time_)
    if not utc:
        if not high_speed:
            df.index = pd.to_datetime(df.index, unit="s")
        else:
            df.index = pd.to_datetime(df.index, unit="ms")
    if df.empty:
        warnings.warn('WARNING- No data retrieved for ' + tag_name + '. ' +
                      'Check eDNA connection, ensure that the start time is ' +
                      'not later than the end time, verify that the ' +
                      'DateTime formatting matches eDNA requirements, and ' +
                      'check that data exists in the query time period.')

    # Check if the user would rather use the description as the column name
    if desc_as_label or label:
        if label:
            new_label = label
        else:
            new_label = _GetLabel(tag_name)
        df.rename(inplace=True, columns={tag_name: new_label,
                  tag_name + " Status": new_label + " Status"})
    return df