From 103727796d6e37444bfbada7d92aea6fd6d27787 Mon Sep 17 00:00:00 2001
From: donker <donker@astron.nl>
Date: Mon, 4 Oct 2021 10:51:56 +0200
Subject: [PATCH] L2SDP-307, working version.

---
 src/constants.h     |   2 +
 src/fpga.cpp        |  13 ++
 src/periph/fpga.cpp | 363 ++++++++++++++++++++++++++++++++++++++++----
 src/periph/fpga.h   |  13 +-
 4 files changed, 359 insertions(+), 32 deletions(-)

diff --git a/src/constants.h b/src/constants.h
index f86fe460..9c2a97ab 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -46,7 +46,9 @@
 
 #define C_Q_fft 2
 #define C_N_sub 512
+#define C_N_pol_bf 2
 #define C_N_sub_bf 488
+#define C_S_sub_bf 488
 #define C_N_step 1
 #define C_N_crosslets_max 7
 #define C_N_scrap 512  // Number of 32 bit words in FPGA scrap memory.
diff --git a/src/fpga.cpp b/src/fpga.cpp
index 4f5ece24..dec7344d 100644
--- a/src/fpga.cpp
+++ b/src/fpga.cpp
@@ -100,6 +100,19 @@ Fpga::Fpga(list<class Node*>& nodelist, const int32_t n_beamsets):
     pointMap->add_register("FPGA_xst_input_bsn_at_sync_R",                   "fpga/xst_input_sync_at_bsn",                  nodes.size(), 1, "RO", REG_FORMAT_INT64);
     pointMap->add_register("FPGA_xst_output_sync_bsn_R",                     "fpga/xst_output_sync_bsn",                    nodes.size(), 1, "RO", REG_FORMAT_INT64);
 
+    pointMap->add_register("FPGA_beamlet_output_enable_R",                      "fpga/beamlet_output_enable",                     nodes.size(), nBeamsets, "RO", REG_FORMAT_BOOLEAN);
+    pointMap->add_register("FPGA_beamlet_output_enable_RW",                     "fpga/beamlet_output_enable",                     nodes.size(), nBeamsets, "RW", REG_FORMAT_BOOLEAN);
+    pointMap->add_register("FPGA_beamlet_output_scale_R",                       "fpga/beamlet_output_scale",                      nodes.size(), nBeamsets, "RO", REG_FORMAT_DOUBLE);
+    pointMap->add_register("FPGA_beamlet_output_scale_RW",                      "fpga/beamlet_output_scale",                      nodes.size(), nBeamsets, "RW", REG_FORMAT_DOUBLE);
+    // pointMap->add_register("FPGA_beamlet_output_nof_beamlets_R",                "fpga/beamlet_output_nof_beamlets",               nodes.size(), 1, "RO", REG_FORMAT_UINT32);
+    // pointMap->add_register("FPGA_beamlet_output_nof_beamlets_RW",               "fpga/beamlet_output_nof_beamlets",               nodes.size(), 1, "RW", REG_FORMAT_UINT32);
+    pointMap->add_register("FPGA_beamlet_output_hdr_eth_destination_mac_R",     "fpga/beamlet_output_hdr_eth_destination_mac",    nodes.size(), nBeamsets, "RO", REG_FORMAT_STRING);
+    pointMap->add_register("FPGA_beamlet_output_hdr_eth_destination_mac_RW",    "fpga/beamlet_output_hdr_eth_destination_mac",    nodes.size(), nBeamsets, "RW", REG_FORMAT_STRING);
+    pointMap->add_register("FPGA_beamlet_output_hdr_ip_destination_address_R",  "fpga/beamlet_output_hdr_ip_destination_address", nodes.size(), nBeamsets, "RO", REG_FORMAT_STRING);
+    pointMap->add_register("FPGA_beamlet_output_hdr_ip_destination_address_RW", "fpga/beamlet_output_hdr_ip_destination_address", nodes.size(), nBeamsets, "RW", REG_FORMAT_STRING);
+    pointMap->add_register("FPGA_beamlet_output_hdr_udp_destination_port_R",    "fpga/beamlet_output_hdr_udp_destination_port",   nodes.size(), nBeamsets, "RO", REG_FORMAT_UINT16);
+    pointMap->add_register("FPGA_beamlet_output_hdr_udp_destination_port_RW",   "fpga/beamlet_output_hdr_udp_destination_port",   nodes.size(), nBeamsets, "RW", REG_FORMAT_UINT16);
+
     pointMap->add_register("FPGA_processing_enable_R",                       "fpga/processing_enable",                      nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN);
     pointMap->add_register("FPGA_processing_enable_RW",                      "fpga/processing_enable",                      nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN);
     pointMap->add_register("FPGA_sdp_info_station_id_R",                     "fpga/sdp_info_station_id",                    nodes.size(), 1, "RO", REG_FORMAT_UINT32);
diff --git a/src/periph/fpga.cpp b/src/periph/fpga.cpp
index 0ecb6275..9bb51e40 100644
--- a/src/periph/fpga.cpp
+++ b/src/periph/fpga.cpp
@@ -124,7 +124,7 @@ bool Periph_fpga::read(TermOutput& termout, const string addr,
 
     termout.datatype = format;
     termout.nof_vals = 0;
-    
+
     if (addr == "fpga/global_node_index") {
         retval = read_global_node_index(termout, format);
         return retval;
@@ -182,10 +182,10 @@ bool Periph_fpga::read(TermOutput& termout, const string addr,
             retval = read_fpga_weights(termout, format);
         }
         else if (addr == "fpga/sst_offload_weighted_subbands") {
-            retval = read_mm_port(termout, "REG_DP_SELECTOR", "input_select", format);
+            retval = read_all_from_port(termout, "REG_DP_SELECTOR", "input_select", format);
         }
         else if (addr == "fpga/sst_offload_enable") {
-            retval = read_mm_port(termout, "REG_STAT_ENABLE_SST", "enable", format);
+            retval = read_all_from_port(termout, "REG_STAT_ENABLE_SST", "enable", format);
         }
         else if (addr == "fpga/sst_offload_hdr_eth_destination_mac") {
             retval = read_sst_offload_hdr_eth_destination_mac(termout, format);
@@ -194,10 +194,10 @@ bool Periph_fpga::read(TermOutput& termout, const string addr,
             retval = read_sst_offload_hdr_ip_destination_address(termout, format);
         }
         else if (addr == "fpga/sst_offload_hdr_udp_destination_port") {
-            retval = read_mm_port(termout, "REG_STAT_HDR_DAT_SST", "udp_destination_port", format);
+            retval = read_all_from_port(termout, "REG_STAT_HDR_DAT_SST", "udp_destination_port", format);
         }
         else if (addr == "fpga/bst_offload_enable") {
-            retval = read_mm_port(termout, "REG_STAT_ENABLE_BST", "enable", format);
+            retval = read_all_from_port(termout, "REG_STAT_ENABLE_BST", "enable", format);
         }
         else if (addr == "fpga/bst_offload_hdr_eth_destination_mac") {
             retval = read_bst_offload_hdr_eth_destination_mac(termout, format);
@@ -206,13 +206,14 @@ bool Periph_fpga::read(TermOutput& termout, const string addr,
             retval = read_bst_offload_hdr_ip_destination_address(termout, format);
         }
         else if (addr == "fpga/bst_offload_hdr_udp_destination_port") {
-            retval = read_mm_port(termout,"REG_STAT_HDR_DAT_BST", "udp_destination_port", format);
+            retval = read_all_from_port(termout,"REG_STAT_HDR_DAT_BST", "udp_destination_port", format);
+            termout.nof_vals = nBeamsets;
         }
         else if (addr == "fpga/xst_offload_enable") {
-            retval = read_mm_port(termout, "REG_STAT_ENABLE_XST", "enable", format);
+            retval = read_all_from_port(termout, "REG_STAT_ENABLE_XST", "enable", format);
         }
         else if (addr == "fpga/xst_offload_nof_crosslets") {
-            retval = read_mm_port(termout, "REG_NOF_CROSSLETS", "nof_crosslets", format);
+            retval = read_all_from_port(termout, "REG_NOF_CROSSLETS", "nof_crosslets", format);
         }
         else if (addr == "fpga/xst_offload_hdr_eth_destination_mac") {
             retval = read_xst_offload_hdr_eth_destination_mac(termout, format);
@@ -221,7 +222,7 @@ bool Periph_fpga::read(TermOutput& termout, const string addr,
             retval = read_xst_offload_hdr_ip_destination_address(termout, format);
         }
         else if (addr == "fpga/xst_offload_hdr_udp_destination_port") {
-            retval = read_mm_port(termout, "REG_STAT_HDR_DAT_XST", "udp_destination_port", format);
+            retval = read_all_from_port(termout, "REG_STAT_HDR_DAT_XST", "udp_destination_port", format);
         }
         else if (addr == "fpga/xst_processing_enable") {
             retval = read_xst_processing_enable(termout, format);
@@ -238,32 +239,52 @@ bool Periph_fpga::read(TermOutput& termout, const string addr,
         else if (addr == "fpga/xst_output_sync_bsn") {
             retval = read_xst_output_sync_bsn(termout, format, R_MEM);
         }
+        else if (addr == "fpga/beamlet_output_enable") {
+            retval = read_all_from_port(termout, "REG_DP_XONOFF", "enable_stream", format);
+            termout.nof_vals = nBeamsets;
+        }
+        else if (addr == "fpga/beamlet_output_scale") {
+            retval = read_beamlet_output_scale(termout, format);
+        }
+        else if (addr == "fpga/beamlet_output_nof_beamlets") {
+            retval = read_beamlet_output_nof_beamlets(termout, format);
+        }
+        else if (addr == "fpga/beamlet_output_hdr_eth_destination_mac") {
+            retval = read_beamlet_output_hdr_eth_destination_mac(termout, format);
+        }
+        else if (addr == "fpga/beamlet_output_hdr_ip_destination_address") {
+            retval = read_beamlet_output_hdr_ip_destination_address(termout, format);
+        }
+        else if (addr == "fpga/beamlet_output_hdr_udp_destination_port") {
+            retval = read_all_from_port(termout, "REG_HDR_DAT", "udp_destination_port", format);
+            termout.nof_vals = nBeamsets;
+        }
         else if (addr == "fpga/processing_enable") {
-            retval = read_mm_port(termout, "REG_BSN_SOURCE_V2", "dp_on", format);
+            retval = read_all_from_port(termout, "REG_BSN_SOURCE_V2", "dp_on", format);
         }
         else if (addr == "fpga/sdp_info_station_id") {
-            retval = read_mm_port(termout, "REG_SDP_INFO", "station_id", format);
+            retval = read_all_from_port(termout, "REG_SDP_INFO", "station_id", format);
         }
         else if (addr == "fpga/sdp_info_observation_id") {
-            retval = read_mm_port(termout, "REG_SDP_INFO", "observation_id", format);
+            retval = read_all_from_port(termout, "REG_SDP_INFO", "observation_id", format);
         }
         else if (addr == "fpga/sdp_info_nyquist_sampling_zone_index") {
-            retval = read_mm_port(termout,"REG_SDP_INFO", "nyquist_zone_index", format);
+            retval = read_all_from_port(termout,"REG_SDP_INFO", "nyquist_zone_index", format);
         }
         else if (addr == "fpga/sdp_info_antenna_band_index") {
-            retval = read_mm_port(termout, "REG_SDP_INFO", "antenna_band_index", format);
+            retval = read_all_from_port(termout, "REG_SDP_INFO", "antenna_band_index", format);
         }
         else if (addr == "fpga/sdp_info_f_adc") {
-            retval = read_mm_port(termout, "REG_SDP_INFO", "f_adc", format);
+            retval = read_all_from_port(termout, "REG_SDP_INFO", "f_adc", format);
         }
         else if (addr == "fpga/sdp_info_fsub_type") {
-            retval = read_mm_port(termout, "REG_SDP_INFO", "fsub_type", format);
+            retval = read_all_from_port(termout, "REG_SDP_INFO", "fsub_type", format);
         }
         else if (addr == "fpga/sdp_info_block_period") {
-            retval = read_mm_port(termout, "REG_SDP_INFO", "block_period", format);
+            retval = read_all_from_port(termout, "REG_SDP_INFO", "block_period", format);
         }
         else if (addr == "fpga/wg_enable") {
-            retval = read_mm_port(termout, "REG_WG", "mode", format);
+            retval = read_all_from_port(termout, "REG_WG", "mode", format);
         }
         else if (addr == "fpga/wg_amplitude") {
             retval = read_wg_amplitude(termout, format);
@@ -305,16 +326,16 @@ bool Periph_fpga::read(TermOutput& termout, const string addr,
             retval = read_signal_input_rms(termout, format, R_MEM);
         }
         else if (addr == "fpga/signal_input_samples_delay") {
-            retval = read_mm_port(termout, "REG_DP_SHIFTRAM", "shift", format);
+            retval = read_all_from_port(termout, "REG_DP_SHIFTRAM", "shift", format);
         }
         else if (addr == "fpga/subband_weights") {
-            retval = read_mm_port(termout, "RAM_EQUALIZER_GAINS", "data", format);
+            retval = read_all_from_port(termout, "RAM_EQUALIZER_GAINS", "data", format);
         }
         else if (addr == "fpga/signal_input_data_buffer") {
-            retval = read_mm_port(termout, "RAM_DIAG_DATA_BUFFER_BSN", "data", format);
+            retval = read_all_from_port(termout, "RAM_DIAG_DATA_BUFFER_BSN", "data", format);
         }
         else if (addr == "fpga/signal_input_histogram") {
-            retval = read_mm_port(termout, "RAM_ST_HISTOGRAM", "data", format);
+            retval = read_all_from_port(termout, "RAM_ST_HISTOGRAM", "data", format);
         }
         else {
             throw runtime_error("address " + addr + " not found!");
@@ -445,6 +466,24 @@ bool Periph_fpga::write(TermOutput& termout, const string addr, const string typ
         else if (addr == "fpga/xst_subband_select") {
             retval = write_xst_subband_select(data);
         }
+        else if (addr == "fpga/beamlet_output_enable") {
+            retval = write_beamlet_output_enable(data);
+        }
+        else if (addr == "fpga/beamlet_output_scale") {
+            retval = write_beamlet_output_scale(data);
+        }
+        else if (addr == "fpga/beamlet_output_nof_beamlets") {
+            retval = write_beamlet_output_nof_beamlets(data);
+        }
+        else if (addr == "fpga/beamlet_output_hdr_eth_destination_mac") {
+            retval = write_beamlet_output_hdr_eth_destination_mac(data);
+        }
+        else if (addr == "fpga/beamlet_output_hdr_ip_destination_address") {
+            retval = write_beamlet_output_hdr_ip_destination_address(data);
+        }
+        else if (addr == "fpga/beamlet_output_hdr_udp_destination_port") {
+            retval = write_beamlet_output_hdr_udp_destination_port(data);
+        }
         else if (addr == "fpga/processing_enable") {
             retval = write_processing_enable(data);
         }
@@ -518,7 +557,7 @@ bool Periph_fpga::monitor(TermOutput& termout)
  from here only intern (private) used functions
 ************************************************/
 
-/* 
+/*
 * Read(), do a read to an UCP register
 * - check if addr_str is available.
 * - get information for reading.
@@ -552,7 +591,7 @@ bool Periph_fpga::Read(const string addr_str, uint32_t *data_ptr, bool use_mask_
     return ret;
 }
 
-/* 
+/*
 * Write(), do a write to an UCP register
 * - check if addr_str is available.
 * - get information for writing.
@@ -675,11 +714,11 @@ bool Periph_fpga::read_system_info(TermOutput& termout)
             my_current_design_name = read_design_name();
             cout << "node " << GlobalNr << " now active design_name = " << my_current_design_name << endl;
         }
-        else { 
+        else {
             return false;
         }
     }
-    
+
     // If the design name is changed clear the mmap.
     string design_name = read_design_name();
     if (design_name != my_current_design_name) {
@@ -693,7 +732,7 @@ bool Periph_fpga::read_system_info(TermOutput& termout)
     my_current_fw_version = to_string(firmware_version) + "." + to_string(firmware_subversion);
     my_current_hw_version = (data[0] & HW_VERSION_MASK) >> HW_VERSION_SHIFT;
     retval = true;
-    
+
     return retval;
 }
 
@@ -1300,6 +1339,261 @@ bool Periph_fpga::write_bst_offload_hdr_udp_destination_port(const char *data)
     return retval;
 }
 
+bool Periph_fpga::write_beamlet_output_enable(const char *data)
+{
+    bool *_ptr = (bool *)data;
+    bool retval = true;
+    string regname;
+    uint32_t _data[1];
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        regname = "mm/" + to_string(i) + "/REG_DP_XONOFF/0/enable_stream";
+        _data[0] = (uint32_t)_ptr[i];
+        retval &= Write(regname, _data);
+    }
+    return retval;
+}
+
+// TODO
+bool Periph_fpga::read_beamlet_output_scale(TermOutput& termout, int format)
+{
+    bool retval = true;
+    string regname;
+    uint32_t W_beamlet_scale = 16;
+    double scale_factor = 1.0 / pow(2.0, (W_beamlet_scale-1));
+    uint32_t data[1];
+    char *_ptr = termout.val;
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        memset((void *)data, 0, sizeof(data));
+        regname = "mm/" + to_string(i) + "/REG_BF_SCALE/0/scale";
+        retval &= Read(regname, data);
+        double scale = (double(data[0]) * scale_factor);
+        memcpy(_ptr, &scale, sizeof(double));
+        _ptr += reg_format_size_in_bytes(format);
+    }
+    termout.nof_vals = nBeamsets;
+    termout.datatype = format;
+    return retval;
+}
+
+// TODO
+bool Periph_fpga::write_beamlet_output_scale(const char *data)
+{
+    double *_ptr = (double *)data;
+    bool retval = true;
+    string regname;
+    uint32_t W_beamlet_scale = 16;
+    double scale_factor = pow(2.0, (W_beamlet_scale-1));
+    uint32_t _data[1];
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        regname = "mm/" + to_string(i) + "/REG_BF_SCALE/0/scale";
+        _data[0] = (uint32_t)(_ptr[i] * scale_factor);
+        retval &= Write(regname, _data);
+    }
+    return retval;
+}
+
+// TODO: REG_DP_BLOCK_RESIZE is not yet supported in the SDPFW.
+bool Periph_fpga::read_beamlet_output_nof_beamlets(TermOutput& termout, int format)
+{
+    bool retval = true;
+    string regname;
+    uint32_t data[2];
+    memset((void *)data, 0, sizeof(data));
+    uint32_t n_beamsets = 0;
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        memset((void *)data, 0, sizeof(data));
+        regname = "mm/" + to_string(i) + "/REG_DP_BLOCK_RESIZE/0/eop_index";
+        retval &= Read(regname, data);
+        n_beamsets += (data[0] + 1) / C_N_pol_bf;
+    }
+    memcpy(termout.val, &n_beamsets, reg_format_size_in_bytes(format));
+    termout.nof_vals = nBeamsets;
+    termout.datatype = format;
+    return retval;
+}
+
+// TODO: REG_DP_BLOCK_RESIZE is not yet supported in the SDPFW.
+bool Periph_fpga::write_beamlet_output_nof_beamlets(const char *data)
+{
+    uint32_t *_ptr = (uint32_t *)data;
+    bool retval = true;
+    string regname;
+    uint32_t nof_beamlets = _ptr[0];
+    uint32_t _data[1] = {0};
+    int32_t bset_data;
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        regname = "mm/" + to_string(i) + "/REG_DP_BLOCK_RESIZE/0/eop_index";
+        // (0+1) * 488 = 488
+        // (1+1) * 488 = 976
+        if (((i + 1) * C_S_sub_bf) < nof_beamlets) {
+            bset_data = (uint32_t)(C_N_pol_bf * C_S_sub_bf - 1);  // 2*488-1 = 975
+        }
+        // (0 * 488) = 0
+        // (1 * 488) = 488
+        else if ((i * C_S_sub_bf) < nof_beamlets) {
+            bset_data = (uint32_t)(C_N_pol_bf * (nof_beamlets - i * C_S_sub_bf) - 1);  // 2*()
+        }
+        else {
+            bset_data = -1;
+        }
+        memcpy(_data, &bset_data, sizeof(int32_t));
+        retval &= Write(regname, _data);
+    }
+    return retval;
+}
+
+
+
+
+bool Periph_fpga::read_beamlet_output_hdr_eth_destination_mac(TermOutput& termout, int format)
+{
+    bool retval = true;
+    string regname;
+
+    uint32_t data[20];
+    // uint64_t mac;
+    stringstream mac_ss;
+    string mac_str;
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        memset((void *)data, 0, sizeof(data));
+        regname = "mm/" + to_string(i) + "/REG_HDR_DAT/0/eth_destination_mac";
+        retval &= Read(regname, data);
+        uint64_t mac = (uint64_t)data[1] << 32 | data[0];
+
+        mac_ss.clear();
+        mac_ss.str("");
+        for (int j=5; j>=0; j--) {
+            mac_ss << setfill('0') << setw(2) << right << hex << ((mac >> (j * 8)) & 0xff);
+            if (j > 0) {
+                mac_ss << ":";
+            }
+        }
+        mac_str = mac_ss.str();
+        // cout << "bst_eth_destination_mac: " << regname << ", data[0]=" << to_string(data[0]) << ", str=" << mac_str << ", retval=" << retval << endl;
+        strcpy(&(termout.val[i*SIZE1STRING]), mac_str.c_str());
+    }
+    termout.nof_vals = nBeamsets;
+    termout.datatype = format;
+    return retval;
+}
+
+bool Periph_fpga::write_beamlet_output_hdr_eth_destination_mac(const char *data)
+{
+    // cout << "data=" << string(data) << endl;
+    bool retval = true;
+    string regname;
+    char sep;
+    uint32_t m0, m1, m2, m3, m4, m5;
+    uint32_t mac[2] {0, 0};
+    string ds;
+    stringstream ss;
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        ss.clear();
+        ss.str("");
+        regname = "mm/" + to_string(i) + "/REG_HDR_DAT/0/eth_destination_mac";
+        ds = &data[i*SIZE1STRING];
+        cout << ds << endl;
+        ss << ds;
+        ss >> setbase(16) >> m0 >> sep >> m1 >> sep >> m2 >> sep >> m3 >> sep >> m4 >> sep >> m5;
+        if (ss.fail() || ss.bad()) {
+            cout << "parse error in write_beamlet_output_hdr_eth_destination_mac (" << ds << ")" << endl;
+            return false;
+        }
+        mac[1] = (m0 << 8) + (m1 << 0);
+        mac[0] = (m2 << 24) + (m3 << 16) + (m4 << 8) + m5;
+        // cout << "mac=" << mac[1] << ", " << mac[0] << endl;
+        retval &= Write(regname, mac);
+    }
+    return retval;
+}
+
+bool Periph_fpga::read_beamlet_output_hdr_ip_destination_address(TermOutput& termout, int format)
+{
+    bool retval = true;
+    string regname;
+
+    uint32_t data[20];
+    stringstream ip_ss;
+    string ip_str;
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        memset((void *)data, 0, sizeof(data));
+        regname = "mm/" + to_string(i) + "/REG_HDR_DAT/0/ip_destination_address";
+        retval &= Read(regname, data);
+        ip_ss.clear();
+        ip_ss.str("");
+        for (int j=3; j>=0; j--) {
+            ip_ss << dec << ((data[0] >> (j * 8)) & 0xff);
+            if (j > 0) {
+                ip_ss << ".";
+            }
+        }
+        ip_str = ip_ss.str();
+        // cout << "bst_ip_destination_address: " << regname << ", data[0]=" << to_string(data[0]) << ", str=" << ip_str << ", retval=" << retval << endl;
+        strcpy(&termout.val[i*SIZE1STRING], ip_str.c_str());
+    }
+    termout.nof_vals = nBeamsets;
+    termout.datatype = format;
+    return retval;
+}
+
+bool Periph_fpga::write_beamlet_output_hdr_ip_destination_address(const char *data)
+{
+    bool retval = true;
+    string regname;
+    char sep;
+    uint ip0, ip1, ip2, ip3;
+    uint32_t ip[1] = {0};
+    string ds;
+    stringstream ss;
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        ss.clear();
+        ss.str("");
+        regname = "mm/" + to_string(i) + "/REG_HDR_DAT/0/ip_destination_address";
+        // cout << "write_ip=[" << ds << "]" << endl;
+        ds = &data[i*SIZE1STRING];
+        cout << ds << endl;
+        ss << ds;
+        ss >> setbase(10) >> ip0;
+        ss >> sep;
+        ss >> setbase(10) >> ip1;
+        ss >> sep;
+        ss >> setbase(10) >> ip2;
+        ss >> sep;
+        ss >> setbase(10) >> ip3;
+        // cout << "ip0=" << to_string(ip0) << " ip1=" << to_string(ip1) << " ip2=" << to_string(ip2) << " ip3=" << to_string(ip3) << endl;
+        if (ss.fail() || ss.bad()) {
+            cout << "parse error in write_beamlet_output_hdr_ip_destination_address (" << ds << ")" << endl;
+            return false;
+        }
+        ip[0]  = (ip0 & 0xff) << 24;
+        ip[0] += (ip1 & 0xff) << 16;
+        ip[0] += (ip2 & 0xff) << 8;
+        ip[0] += ip3 & 0xff;
+        cout << "ip=" << hex << ip[0] << endl;
+        if (Write(regname, ip) == false) {
+            retval = false;
+        }
+    }
+    return retval;
+}
+
+bool Periph_fpga::write_beamlet_output_hdr_udp_destination_port(const char *data)
+{
+    uint32_t *_ptr = (uint32_t *)data;
+    bool retval = true;
+    string regname;
+    for (uint32_t i=0; i<nBeamsets; i++) {
+        regname = "mm/" + to_string(i) + "/REG_HDR_DAT/0/udp_destination_port";
+        retval &= Write(regname, &_ptr[i]);
+    }
+    return retval;
+}
+
+
+
+
+
+
 bool Periph_fpga::write_xst_offload_enable(const char *data)
 {
     uint32_t _data[1];
@@ -1550,6 +1844,11 @@ bool Periph_fpga::write_xst_subband_select(const char *data)
     return retval;
 }
 
+
+
+
+
+
 bool Periph_fpga::write_processing_enable(const char *data)
 {
     // write dp_on 0
@@ -1557,7 +1856,7 @@ bool Periph_fpga::write_processing_enable(const char *data)
     // write bsn_time_offset [calc val if odd]
     // write dp_on_pps 1
     // write dp_on 1
-    
+
     uint32_t *reg = new uint32_t[2];
     reg[0] = 0;
     reg[1] = 0;
@@ -2133,7 +2432,7 @@ bool Periph_fpga::write_subband_weights(const char *data) {
     return retval;
 }
 
-bool Periph_fpga::read_mm_port(TermOutput& termout, const string& port_name, const string& field_name, const int format) {
+bool Periph_fpga::read_all_from_port(TermOutput& termout, const string& port_name, const string& field_name, const int format) {
     bool retval = true;
 
     string regname = "mm/0/" + port_name + "/0/" + field_name;
@@ -2158,10 +2457,12 @@ bool Periph_fpga::read_mm_port(TermOutput& termout, const string& port_name, con
                 // if a string
                 if (format == REG_FORMAT_STRING) {
                     memcpy(_ptr, data, n_fields);
+                    _ptr += SIZE1STRING;
                 }
                 // if >= 4 bytes (uint32_t)
                 else if (format_size >= sizeof(uint32_t)) {
                     memcpy(_ptr, data, (n_fields * format_size));
+                    _ptr += (n_fields * format_size);
                 }
                 // if < 4 (uint32_t)
                 else {
@@ -2173,7 +2474,7 @@ bool Periph_fpga::read_mm_port(TermOutput& termout, const string& port_name, con
             }
             // not valid data, set pointer to memory for next port data
             else {
-                _ptr += format_size * n_fields;
+                _ptr += (format_size * n_fields);
             }
         }
     }
@@ -2198,7 +2499,7 @@ bool Periph_fpga::read_mm_port(TermOutput& termout, const string& port_name, con
     for (uint i=0; i<n_periph; i++) {
         for (uint j=0; j<n_ports; j++) {
             regname = "mm/" + to_string(i) + "/" + port_name + "/" + to_string(j) + "/" + field_name;
-            
+
             for (uint field_nr=0; field_nr<n_fields; field_nr++) {
                 memcpy(&reg[field_nr], _ptr, format_size);
                 _ptr += format_size;
diff --git a/src/periph/fpga.h b/src/periph/fpga.h
index 6fd29266..089f72b2 100644
--- a/src/periph/fpga.h
+++ b/src/periph/fpga.h
@@ -128,6 +128,17 @@ private:
   bool read_bst_offload_nof_beamlets_per_packet(TermOutput& termout, int format);
   bool write_bst_offload_nof_beamlets_per_packet(const char *data);
 
+  bool write_beamlet_output_enable(const char *data);
+  bool read_beamlet_output_scale(TermOutput& termout, int format);
+  bool write_beamlet_output_scale(const char *data);
+  bool read_beamlet_output_nof_beamlets(TermOutput& termout, int format);
+  bool write_beamlet_output_nof_beamlets(const char *data);
+  bool read_beamlet_output_hdr_eth_destination_mac(TermOutput& termout, int format);
+  bool write_beamlet_output_hdr_eth_destination_mac(const char *data);
+  bool read_beamlet_output_hdr_ip_destination_address(TermOutput& termout, int format);
+  bool write_beamlet_output_hdr_ip_destination_address(const char *data);
+  bool write_beamlet_output_hdr_udp_destination_port(const char *data);
+
   bool read_xst_subband_select(TermOutput& termout, int format);
   bool write_xst_subband_select(const char *data);
   bool read_xst_input_sync_at_bsn(TermOutput& termout, int format, int mode);
@@ -178,7 +189,7 @@ private:
   bool read_time_since_last_pps(TermOutput& termout, int format, int mode);
   bool write_wdi_override(TermOutput& termout);
 
-  bool read_mm_port(TermOutput& termout, const std::string& port_name, const std::string& field_name, const int format);
+  bool read_all_from_port(TermOutput& termout, const std::string& port_name, const std::string& field_name, const int format);
 
   CMMap read_reg_map();
 
-- 
GitLab