예제 #1
0
def encode_section3(message: dict, context: dict):
    """Encodes section 3."""
    buf = context['buf']
    section3 = message['section3']
    start = buf.tell()
    buf.seek(start + 3)
    buf.write(b'\x00')  # Set to 0 per standard
    number_of_subsets = shift_uint(section3['number_of_subsets'], 16, 0, 16)
    buf.write(number_of_subsets)
    flags_byte = 0
    if section3['observed_flag']:
        flags_byte |= 0x80
    if section3['compressed_flag']:
        flags_byte |= 0x40
    buf.write(bytes([flags_byte]))

    for descriptor in section3['descriptors']:
        f, x, y = parse_ref(descriptor)
        fx = bytearray(1)
        fx = encode_uint(fx, f, 0, 2)
        fx = encode_uint(fx, x, 2, 6)
        buf.write(fx)
        buf.write(bytes([y]))

    end = buf.tell()
    section_len = end - start
    buf.seek(start)
    section_len_b = shift_uint(section_len, 24, 0, 24)
    buf.write(section_len_b)
    buf.seek(end)
예제 #2
0
def get_sequence_description(fxy_str: str) -> pd.DataFrame:
    """Returns a sequence description used for encoding/decoding."""
    summary = get_summary(fxy_str).copy(deep=True)
    # Get rid of the old index because it references a combination of other tables
    summary.reset_index(drop=True, inplace=True)
    summary.rename(columns={
        'BUFR_Scale': 'scale',
        'BUFR_ReferenceValue': 'offset',
        'FXY': 'fxy',
        'Parent': 'parent',
        'BUFR_DataWidth_Bits': 'bit_len',
    },
                   inplace=True)
    summary['type'] = np.nan
    summary['text'] = summary['Title']
    for i, row in summary.iterrows():
        f, x, y = parse_ref(row['fxy'])
        typename = ''
        title = f'{row["Title"]} ({row["BUFR_Unit"]})'
        if f == 2:
            typename = 'operator'
        elif row['BUFR_Unit'] == 'CCITT IA5':
            typename = 'string'
        elif row['BUFR_Unit'] == 'Replication':
            typename = 'replication'
        else:
            typename = 'numeric'
        summary.iloc[i, summary.columns.get_loc('type')] = typename
        summary.iloc[i, summary.columns.get_loc('text')] = title
    return summary
예제 #3
0
def table_d_lookup(f, x, y, parent=None):
    """Returns a data frame for a Table D."""
    df = get_table_d(f, x, y)
    sub_references = []
    fxy_str = f'{f}{x:02d}{y:03d}'
    if parent is None:
        title = df.iloc[0]['Title_en']
        subtitle = ''
        sub_references.append((fxy_str, fxy_str, title, subtitle))
        parent = fxy_str
    for index, row in df.iterrows():
        ref = row['FXY2']
        title = row['ElementName_en']
        subtitle = row['ElementDescription_en']
        ref_f, ref_x, ref_y = parse_ref(ref)
        if ref_f == 0:
            sub_references.append((parent, ref, title, subtitle))
        if ref_f == 2 and ref_x == 8:
            sub_references.append((parent, ref, title, subtitle))
        if ref_f == 1:
            sub_references.append((parent, ref, title, subtitle))
        if ref_f == 3:
            sub_references.append((parent, ref, title, subtitle))
            sub_refs = table_d_lookup(ref_f, ref_x, ref_y, ref)
            sub_references.extend(sub_refs)
    return sub_references
예제 #4
0
def encode_section4(message: dict, context: dict):
    """Encodes section 4."""
    buf = context['buf']
    write_buf = io.BytesIO()
    start = buf.tell()
    buf.seek(start + 3)
    buf.write(b'\x00')

    bit_offset = 0
    sequence = message['section4'][:]
    override_bitlength = None
    for seq in sequence:
        # Deal with operators
        if seq['type'] == 'operator':
            f, x, y = parse_ref(seq['fxy'])
            if (f, x) == (2, 8):
                if y > 0:
                    override_bitlength = y * 8
                else:
                    override_bitlength = None
            continue
        if seq['bit_len'] < 1:
            # Skip 0-length sections, they're for information purposes only
            continue
        if seq['type'] == 'numeric':
            bitlen = seq['bit_len']
            if override_bitlength:
                bitlen = override_bitlength
            value = float(seq['value'])
            if seq['scale']:
                value = value * math.pow(10, seq['scale'])
            if seq['offset']:
                value = value - seq['offset']
            # The value should be ROUNDED to the nearest integer
            value = int(np.round(value))
            write_uint(write_buf, value, bit_offset, bitlen)
            bit_offset += seq['bit_len']
        elif seq['type'] == 'string':
            bitlen = seq['bit_len']
            if override_bitlength:
                bitlen = override_bitlength
            write_ascii(write_buf, seq['value'], bit_offset, bitlen)
            bit_offset += seq['bit_len']

    write_buf.seek(0)
    buf.write(write_buf.read())
    # Write section length
    end = buf.tell()
    section_len = end - start
    section_len_b = shift_uint(section_len, 24, 0, 24)
    buf.seek(start)
    buf.write(section_len_b)
    buf.seek(end)
예제 #5
0
def get_summary(fxy_str: str) -> pd.DataFrame:
    """Returns a summary table of the contents of the FXXYYY sequence."""
    f, x, y = parse_ref(fxy_str)
    references = table_d_lookup(f, x, y)
    df = combine_references(references)
    columns = [
        'Parent',
        'FXY',
        'Title',
        'Subtitle',
        'BUFR_DataWidth_Bits',
        'BUFR_Unit',
        'BUFR_Scale',
        'BUFR_ReferenceValue',
    ]
    return df[columns]
예제 #6
0
def get_code_table_figure(fxy_str: str, code_figure: int) -> dict:
    """Returns the code table row for the given FXXYYY string."""
    f, x, y = parse_ref(fxy_str)
    filename = f'BUFRCREX_CodeFlag_en_{x:02d}.csv'
    utf8_reader = codecs.getreader('utf-8')
    with pkg_resources.resource_stream('bufrtools.tables',
                                       f'data/{filename}') as f:
        reader = csv.DictReader(utf8_reader(f))
        for row in reader:
            if fxy_str != row['FXY']:
                continue
            if '-' in row['CodeFigure']:
                start, end = (int(i) for i in row['CodeFigure'].split('-'))
                if start <= code_figure and code_figure <= end:
                    return row
            else:
                try:
                    val = int(row['CodeFigure'])
                    if val == code_figure:
                        return row
                except ValueError:
                    pass
예제 #7
0
def get_code_table(fxy_str: str) -> pd.DataFrame:
    """Returns the code table for the given FXXYYY string."""
    f, x, y = parse_ref(fxy_str)
    filename = f'BUFRCREX_CodeFlag_en_{x:02d}.csv'
    utf8_reader = codecs.getreader('utf-8')
    with pkg_resources.resource_stream('bufrtools.tables',
                                       f'data/{filename}') as f:
        reader = csv.DictReader(utf8_reader(f))
        rows = []
        for row in reader:
            if fxy_str != row['FXY']:
                continue
            if '-' in row['CodeFigure']:
                start, end = (int(i) for i in row['CodeFigure'].split('-'))
                for i in range(start, end + 1):
                    enumerated_row = copy.copy(row)
                    enumerated_row['CodeFigure'] = i
                    rows.append(enumerated_row)
            else:
                rows.append(row)
    df = pd.DataFrame(rows)
    df = df.astype({'CodeFigure': np.uint16})
    return df
예제 #8
0
def combine_references(references) -> pd.DataFrame:
    """Returns a data frame for a generic reference, that will be flattened."""
    frames = []
    for parent, reference, title, subtitle in references:
        f, x, y = parse_ref(reference)
        if f == 2 and x == 8:
            frames.append(
                pd.DataFrame([{
                    'Parent': parent,
                    'FXY': f'{f}{x:02d}{y:03d}',
                    'ElementName_en':
                    f'Operator Change CCITT IA5 width to {8 * y}',
                    'BUFR_DataWidth_Bits': 0,
                    'BUFR_Unit': 'Operator',
                    'Title': title,
                    'Subtitle': subtitle,
                }]))
        elif f == 1:
            if y == 0:
                frames.append(
                    pd.DataFrame([{
                        'Parent': parent,
                        'FXY': f'{f}{x:02d}{y:03d}',
                        'ClassName_en': 'Replication',
                        'ElementName_en': f'Delayed Replication: {x}',
                        'BUFR_DataWidth_Bits': 0,
                        'BUFR_Unit': 'Replication',
                        'Title': title,
                        'Subtitle': subtitle,
                    }]))
            else:
                frames.append(
                    pd.DataFrame([{
                        'Parent': parent,
                        'FXY': f'{f}{x:02d}{y:03d}',
                        'ClassName_en': 'Replication',
                        'ElementName_en': f'Replication {x}',
                        'BUFR_DataWidth_Bits': 0,
                        'BUFR_Unit': 'Replication',
                        'Title': title,
                        'Subtitle': subtitle,
                    }]))
        elif f == 3:
            df = get_table_d(f, x, y)
            name = df.iloc[0]['Title_en']
            frames.append(
                pd.DataFrame([{
                    'Parent': parent,
                    'FXY': f'{f}{x:02d}{y:03d}',
                    'ClassName_en': 'sequence',
                    'ElementName_en': f'{name}',
                    'BUFR_DataWidth_Bits': 0,
                    'BUFR_Unit': 'Sequence',
                    'Title': title,
                    'Subtitle': subtitle,
                }]))
        else:
            df = get_table_b(f, x, y)
            df['Parent'] = parent
            df['Title'] = title
            df['Subtitle'] = subtitle
            frames.append(df)
    return pd.concat(frames)