Matlab

parseFeitCSI.m
%{
Function which parse FeitCSI data.
usage: parseFeitCSI("path/to/FeitCSI/file")
returned data structure sample:
[
    {
        header: {
            "csi_size":416,
            "ftm_clock":144084200,
            "num_rx":2,
            "num_tx":1,
            "num_subcarriers":52,
            "rssi1":67,
            "rssi2":68,
            "source_mac":(0, 7, 14, 124, 232, 48),
            "source_mac_string":"00:07:0e:7c:e8:30",
            "rate_flags":49415,
            "rate_format":"LEGACY_OFDM",
            "channel_width":"20",
            "mcs":7,
            "antenna_a":true,
            "antenna_b":true,
            "ldpc":false,
            "ss":1,
            "beamforming":false
        },
        data: complex matrix[num_subcarriers, num_rx, num_tx]
    },
    {
        header: ...,
        data: ...
    }, 
    ...
]
%}

function output = parseFeitCSI(fileName)
    RATE_MCS_MOD_TYPE_POS = uint32(8);
    RATE_MCS_MOD_TYPE_MSK = bitshift(uint32(0x7), RATE_MCS_MOD_TYPE_POS);
    RATE_MCS_CCK_MSK = bitshift(uint32(0), RATE_MCS_MOD_TYPE_POS);
    RATE_MCS_LEGACY_OFDM_MSK = bitshift(uint32(1), RATE_MCS_MOD_TYPE_POS);
    RATE_MCS_HT_MSK = bitshift(uint32(2), RATE_MCS_MOD_TYPE_POS);
    RATE_MCS_VHT_MSK = bitshift(uint32(3), RATE_MCS_MOD_TYPE_POS);
    RATE_MCS_HE_MSK = bitshift(uint32(4), RATE_MCS_MOD_TYPE_POS);
    RATE_MCS_EHT_MSK = bitshift(uint32(5), RATE_MCS_MOD_TYPE_POS);
    RATE_MCS_CHAN_WIDTH_POS = uint32(11);
    RATE_MCS_CHAN_WIDTH_MSK = bitshift(uint32(0x7), RATE_MCS_CHAN_WIDTH_POS);
    RATE_MCS_CHAN_WIDTH_20_VAL = uint32(0);
    RATE_MCS_CHAN_WIDTH_20 = bitshift(RATE_MCS_CHAN_WIDTH_20_VAL, RATE_MCS_CHAN_WIDTH_POS);
    RATE_MCS_CHAN_WIDTH_40_VAL = uint32(1);
    RATE_MCS_CHAN_WIDTH_40 = bitshift(RATE_MCS_CHAN_WIDTH_40_VAL, RATE_MCS_CHAN_WIDTH_POS);
    RATE_MCS_CHAN_WIDTH_80_VAL = uint32(2);
    RATE_MCS_CHAN_WIDTH_80 = bitshift(RATE_MCS_CHAN_WIDTH_80_VAL, RATE_MCS_CHAN_WIDTH_POS);
    RATE_MCS_CHAN_WIDTH_160_VAL = uint32(3);
    RATE_MCS_CHAN_WIDTH_160 = bitshift(RATE_MCS_CHAN_WIDTH_160_VAL, RATE_MCS_CHAN_WIDTH_POS);
    RATE_MCS_CHAN_WIDTH_320_VAL = uint32(4);
    RATE_MCS_CHAN_WIDTH_320 = bitshift(RATE_MCS_CHAN_WIDTH_320_VAL, RATE_MCS_CHAN_WIDTH_POS);
    RATE_HT_MCS_CODE_MSK = uint32(7);
    RATE_MCS_ANT_A_POS = uint32(14);
    RATE_MCS_ANT_A_MSK = bitshift(uint32(1), RATE_MCS_ANT_A_POS);
    RATE_MCS_ANT_B_POS = uint32(15);
    RATE_MCS_ANT_B_MSK = bitshift(uint32(1), RATE_MCS_ANT_B_POS);
    RATE_MCS_LDPC_POS = uint32(16);
    RATE_MCS_LDPC_MSK = bitshift(uint32(1), RATE_MCS_LDPC_POS);
    RATE_MCS_SS_POS = uint32(16);
    RATE_MCS_SS_MSK = bitshift(uint32(1), RATE_MCS_SS_POS);
    RATE_MCS_BEAMF_POS = uint32(16);
    RATE_MCS_BEAMF_MSK = bitshift(uint32(1), RATE_MCS_BEAMF_POS);

    function header = parseHeader(data)
        header = {};
        header.csi_size = typecast(data(1:4), 'uint32');
        header.ftm_clock = typecast(data(9:12), 'uint32');
        header.num_rx = data(47);
        header.num_tx = data(48);
        header.num_subcarriers = typecast(data(53:56), 'uint32');
        header.rssi1 = typecast(data(61:64), 'uint32');
        header.rssi2 = typecast(data(65:68), 'uint32');
        header.source_mac = data(69:74);
        header.source_mac_string = sprintf('%02x:%02x:%02x:%02x:%02x:%02x', header.source_mac);
        header.rate_flags = typecast(data(93:96), 'uint32');

        rate_format = bitand(header.rate_flags, RATE_MCS_MOD_TYPE_MSK);
        if rate_format == RATE_MCS_CCK_MSK
            rate_format = 'CCK';
        elseif rate_format == RATE_MCS_LEGACY_OFDM_MSK
            rate_format = 'LEGACY_OFDM';
        elseif rate_format == RATE_MCS_VHT_MSK
            rate_format = 'VHT';
        elseif rate_format == RATE_MCS_HT_MSK
            rate_format = 'HT';
        elseif rate_format == RATE_MCS_HE_MSK
            rate_format = 'HE';
        elseif rate_format == RATE_MCS_EHT_MSK
            rate_format = 'EHT';
        else
            rate_format = 'unknown';
        end
        header.rate_format = rate_format;

        channel_width = bitand(header.rate_flags, RATE_MCS_CHAN_WIDTH_MSK);
        if channel_width == RATE_MCS_CHAN_WIDTH_20
            channel_width = '20';
        elseif channel_width == RATE_MCS_CHAN_WIDTH_40
            channel_width = '40';
        elseif channel_width == RATE_MCS_CHAN_WIDTH_80
            channel_width = '80';
        elseif channel_width == RATE_MCS_CHAN_WIDTH_160
            channel_width = '160';
        elseif channel_width == RATE_MCS_CHAN_WIDTH_320
            channel_width = '320';
        else
            channel_width = 'unknown';
        end
        header.channel_width = channel_width;

        header.mcs = bitand(header.rate_flags, RATE_HT_MCS_CODE_MSK);

        if bitand(header.rate_flags, RATE_MCS_ANT_A_MSK)
            header.antenna_a = true;
        else    
            header.antenna_a = false;
        end

        if bitand(header.rate_flags, RATE_MCS_ANT_B_MSK)
            header.antenna_b = true;
        else    
            header.antenna_b = false;
        end

        if bitand(header.rate_flags, RATE_MCS_LDPC_MSK)
            header.ldpc = true;
        else    
            header.ldpc = false;
        end

        if bitand(header.rate_flags, RATE_MCS_SS_MSK)
            header.ss = 2;
        else    
            header.ss = 1;
        end

        if bitand(header.rate_flags, RATE_MCS_BEAMF_MSK)
            header.beamforming = true;
        else    
            header.beamforming = false;
        end

    end


    function csi_matrix = parseCsiData(data, header)
        csi_matrix = zeros(header.num_subcarriers, header.num_rx, header.num_tx);
        csi_matrix  = complex(csi_matrix ,0);
        pos = 1;
        for j = 1:header.num_rx
            for k = 1:header.num_tx
                for n = 1:header.num_subcarriers
                    real = typecast(data(pos:pos + 1), 'int16');
                    imag = typecast(data(pos + 2:pos + 3), 'int16');
                    pos = pos + 4;
                    csi_matrix(n, j, k) = complex(real, imag);
                end
            end
        end
    end

    f = fopen(fileName);
    fileContent = uint8(fread(f));
    step = 1;
    index = 1;
    while length(fileContent) > step
        data = {};
        data.header = parseHeader(fileContent(step:step + 271));
        step = step + 272;
        data.csi_matrix = parseCsiData(fileContent(step:step+data.header.csi_size - 1), data.header);
        step = step + data.header.csi_size;
        output(index ) = data;
        index  = index  + 1;
    end
end