From 57e5e16f2f1e41a2b34d6c7eecfd55e776844b10 Mon Sep 17 00:00:00 2001
From: donker <donker@astron.nl>
Date: Wed, 28 Jul 2021 23:27:13 +0200
Subject: [PATCH] L2SDP-349, add bst_offload, and a lot other stuff to make n
 instanches and multiple strings per node per point possible.

---
 src/constants.h         |   1 +
 src/fpga.cpp            |  64 +++++----
 src/fpga.h              |   2 +-
 src/map.cpp             |   6 +-
 src/map.h               |   2 +-
 src/node.cpp            |  10 +-
 src/opcua/ua_server.cpp |  21 ++-
 src/periph/fpga.cpp     | 311 ++++++++++++++++++++++++++++++++++++++--
 src/periph/fpga.h       |  15 +-
 src/tools/mmap.cpp      |  47 +++---
 src/tools/util.h        |  49 -------
 11 files changed, 397 insertions(+), 131 deletions(-)

diff --git a/src/constants.h b/src/constants.h
index 3f399ebe..b8df1d7c 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -44,5 +44,6 @@
 
 #define C_Q_fft 2
 #define C_N_sub 512
+#define C_N_beamsets 2
 
 #endif
diff --git a/src/fpga.cpp b/src/fpga.cpp
index 3e18f3a1..bd03ebcc 100644
--- a/src/fpga.cpp
+++ b/src/fpga.cpp
@@ -61,6 +61,7 @@ Fpga::Fpga(list<class Node*>& nodelist)
     pointMap->add_register("FPGA_version_R",                                 "fpga/name",                                   nodes.size(), 1, "RO", REG_FORMAT_STRING);
     pointMap->add_register("FPGA_firmware_version_R",                        "fpga/firmware_version",                       nodes.size(), 1, "RO", REG_FORMAT_STRING);
     pointMap->add_register("FPGA_hardware_version_R",                        "fpga/hardware_version",                       nodes.size(), 1, "RO", REG_FORMAT_STRING);
+
     pointMap->add_register("FPGA_sst_offload_weighted_subbands_R",           "fpga/sst_offload_weighted_subbands",          nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN);
     pointMap->add_register("FPGA_sst_offload_weighted_subbands_RW",          "fpga/sst_offload_weighted_subbands",          nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN);
     pointMap->add_register("FPGA_sst_offload_enable_R",                      "fpga/sst_offload_enable",                     nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN);
@@ -71,6 +72,19 @@ Fpga::Fpga(list<class Node*>& nodelist)
     pointMap->add_register("FPGA_sst_offload_hdr_ip_destination_address_RW", "fpga/sst_offload_hdr_ip_destination_address", nodes.size(), 1, "RW", REG_FORMAT_STRING);
     pointMap->add_register("FPGA_sst_offload_hdr_udp_destination_port_R",    "fpga/sst_offload_hdr_udp_destination_port",   nodes.size(), 1, "RO", REG_FORMAT_UINT16);
     pointMap->add_register("FPGA_sst_offload_hdr_udp_destination_port_RW",   "fpga/sst_offload_hdr_udp_destination_port",   nodes.size(), 1, "RW", REG_FORMAT_UINT16);
+
+    pointMap->add_register("FPGA_bst_offload_enable_R",                      "fpga/bst_offload_enable",                     nodes.size(), C_N_beamsets, "RO", REG_FORMAT_BOOLEAN);
+    pointMap->add_register("FPGA_bst_offload_enable_RW",                     "fpga/bst_offload_enable",                     nodes.size(), C_N_beamsets, "RW", REG_FORMAT_BOOLEAN);
+    pointMap->add_register("FPGA_bst_offload_hdr_eth_destination_mac_R",     "fpga/bst_offload_hdr_eth_destination_mac",    nodes.size(), C_N_beamsets, "RO", REG_FORMAT_STRING);
+    pointMap->add_register("FPGA_bst_offload_hdr_eth_destination_mac_RW",    "fpga/bst_offload_hdr_eth_destination_mac",    nodes.size(), C_N_beamsets, "RW", REG_FORMAT_STRING);
+    pointMap->add_register("FPGA_bst_offload_hdr_ip_destination_address_R",  "fpga/bst_offload_hdr_ip_destination_address", nodes.size(), C_N_beamsets, "RO", REG_FORMAT_STRING);
+    pointMap->add_register("FPGA_bst_offload_hdr_ip_destination_address_RW", "fpga/bst_offload_hdr_ip_destination_address", nodes.size(), C_N_beamsets, "RW", REG_FORMAT_STRING);
+    pointMap->add_register("FPGA_bst_offload_hdr_udp_destination_port_R",    "fpga/bst_offload_hdr_udp_destination_port",   nodes.size(), C_N_beamsets, "RO", REG_FORMAT_UINT16);
+    pointMap->add_register("FPGA_bst_offload_hdr_udp_destination_port_RW",   "fpga/bst_offload_hdr_udp_destination_port",   nodes.size(), C_N_beamsets, "RW", REG_FORMAT_UINT16);
+    // pointMap->add_register("FPGA_bst_offload_nof_beamlets_per_packet_R",     "fpga/bst_offload_nof_beamlets_per_packet",    nodes.size(), C_N_beamsets, "RO", REG_FORMAT_UINT32);
+    // pointMap->add_register("FPGA_bst_offload_nof_beamlets_per_packet_RW",    "fpga/bst_offload_nof_beamlets_per_packet",    nodes.size(), C_N_beamsets, "RW", REG_FORMAT_UINT32);
+
+
     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);
@@ -97,15 +111,15 @@ Fpga::Fpga(list<class Node*>& nodelist)
     pointMap->add_register("FPGA_bsn_monitor_input_nof_packets_R",           "fpga/bsn_monitor_input_nof_packets",          nodes.size(), 1, "RO", REG_FORMAT_INT32);
     pointMap->add_register("FPGA_bsn_monitor_input_nof_valid_R",             "fpga/bsn_monitor_input_nof_valid",            nodes.size(), 1, "RO", REG_FORMAT_INT32);
     pointMap->add_register("FPGA_bsn_monitor_input_nof_err_R",               "fpga/bsn_monitor_input_nof_err",              nodes.size(), 1, "RO", REG_FORMAT_INT32);
-    
+
     pointMap->add_register("FPGA_jesd204b_csr_rbd_count_R",                  "fpga/jesd204b_csr_rbd_count",                 nodes.size(), C_S_pn, "RO", REG_FORMAT_UINT32);
     pointMap->add_register("FPGA_jesd204b_csr_dev_syncn_R",                  "fpga/jesd204b_csr_dev_syncn",                 nodes.size(), C_S_pn, "RO", REG_FORMAT_UINT32);
     pointMap->add_register("FPGA_jesd204b_rx_err0_R",                        "fpga/jesd204b_csr_rx_err0",                   nodes.size(), C_S_pn, "RO", REG_FORMAT_UINT32);
     pointMap->add_register("FPGA_jesd204b_rx_err1_R",                        "fpga/jesd204b_csr_rx_err1",                   nodes.size(), C_S_pn, "RO", REG_FORMAT_UINT32);
-    
+
     pointMap->add_register("FPGA_signal_input_samples_delay_R",              "fpga/signal_input_samples_delay",             nodes.size(), C_S_pn, "RO", REG_FORMAT_UINT32);
     pointMap->add_register("FPGA_signal_input_samples_delay_RW",             "fpga/signal_input_samples_delay",             nodes.size(), C_S_pn, "RW", REG_FORMAT_UINT32);
-    
+
     pointMap->add_register("FPGA_subband_weights_R",                         "fpga/subband_weights",                        nodes.size(), C_S_pn*C_N_sub, "RO", REG_FORMAT_UINT32);
     pointMap->add_register("FPGA_subband_weights_RW",                        "fpga/subband_weights",                        nodes.size(), C_S_pn*C_N_sub, "RW", REG_FORMAT_UINT32);
 
@@ -124,7 +138,7 @@ Fpga::Fpga(list<class Node*>& nodelist)
     cout << "scrap_span=" << scrap_span << endl;
     pointMap->add_register("FPGA_scrap_R",                                   "fpga/scrap",                                  nodes.size(), scrap_span, "RO", REG_FORMAT_UINT32);
     pointMap->add_register("FPGA_scrap_RW",                                  "fpga/scrap",                                  nodes.size(), scrap_span, "RW", REG_FORMAT_UINT32);
-    
+
     uint32_t weights_span = 0;
     uint32_t weights_span_next = 0;
     uint32_t weights_span_prev = 0;
@@ -188,7 +202,7 @@ CPointMap * Fpga::get_pointMap(void)
 }
 
 bool Fpga::point(TermOutput& termout, const char cmd, const string addr,
-                 const unsigned int *data, CMData& cm, const int nvalues)
+                 const unsigned int *data, const int nvalues)
 {
     bool ret, retval = false;
     uint retcnt = 0;
@@ -232,37 +246,25 @@ bool Fpga::point(TermOutput& termout, const char cmd, const string addr,
 
         CPointMap *regmap = node->get_RegisterMap();
         int span = regmap->getDataSize(relative_addr);
-        
+
         int nof_values = nvalues;
         if (nvalues < 0 || nvalues > span) {
             nof_values = span;
         }
 
         ret = false;
-        bool done = false;
         try {
-            if ((cmd == 'W') && (cm.getFormat() == FORMAT_STRING)) {
-                uint *data2 = new uint[20];
-                memset((void *)data2, 0, sizeof(data2));
-                cout << "str=" << cm.getStr(idx) << " len=" << cm.getStrLen(idx) << endl;
-                memcpy((void *)data2, (void *)cm.getStrPtr(idx), cm.getStrLen(idx));
-                nof_values = cm.getStrLen(idx);
-                if ((ret = node->exec_cmd(cmd, relative_addr, type, instance,
-                                          data2, nof_values, format))) {
-                    retcnt++;
-                    done = true;
-                }
-                delete[] data2;
-            }
-            if (!done) {
-                uint didx = 0;
-                if (cmd == 'W') {
+            uint didx = 0;
+            if (cmd == 'W') {
+                if (format == REG_FORMAT_STRING) {
+                    didx = idx * nof_values * (SIZE1STRING/4);
+                } else {
                     didx = idx * nof_values;
                 }
-                if ((ret = node->exec_cmd(cmd, relative_addr, type, instance,
-                                          &data[didx], nof_values*sizeof(unsigned int), format))) {
-                    retcnt++;
-                }
+            }
+            if ((ret = node->exec_cmd(cmd, relative_addr, type, instance,
+                                      &data[didx], nof_values, format))) {
+                retcnt++;
             }
         } catch (exception& e) {
             cerr << e.what() << endl;
@@ -357,8 +359,12 @@ bool Fpga::point(TermOutput& termout, const char cmd, const string addr,
                 case REG_FORMAT_STRING: {
                     char *ptr_in = (char *)termresults.val;
                     char *ptr_out = (char *)termout.val;
-                    ptr_out += (idx * SIZE1STRING);
-                    strcpy(ptr_out, ptr_in);
+                    ptr_out += (idx * termresults.nof_vals * SIZE1STRING);
+                    for (unsigned int i=0; i<termresults.nof_vals; i++) {
+                        ptr_in += (i * SIZE1STRING);
+                        ptr_out += (i * SIZE1STRING);
+                        strcpy(ptr_out, ptr_in);
+                    }
                 } break;
                 default: {
                     cout << "fpga-r320, Not supported datatype (" << termresults.datatype << " in " << addr << endl;
diff --git a/src/fpga.h b/src/fpga.h
index 1cc3a839..cfa1ca83 100644
--- a/src/fpga.h
+++ b/src/fpga.h
@@ -49,7 +49,7 @@ public:
     ~Fpga();
 
     bool point(TermOutput& termout, const char cmd, const std::string addr,
-               const unsigned int *data, CMData& cm, const int len);
+               const unsigned int *data, const int len);
 
     Node * select_node(const int nr);
     std::vector<int> get_all_nodes(void);
diff --git a/src/map.cpp b/src/map.cpp
index 3b4a1cce..eb605595 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -59,8 +59,7 @@ bool UniboardMap::read(TermOutput& termout,
     bool retval = false;
     if (is_fpga(addr)) { // addressed with FPGA_...
         //cout << "UniboardMap::read fpga application" << endl;
-        CMData cm;
-        retval = point(termout, 'R', addr, NULL, cm, nvalues);
+        retval = point(termout, 'R', addr, NULL, nvalues);
     }
     return retval;
 }
@@ -69,13 +68,12 @@ bool UniboardMap::read(TermOutput& termout,
 bool UniboardMap::write(TermOutput& termout,
                         const string addr,
                         const unsigned int *data,
-                        CMData& cm,
                         const int nvalues)
 {
     bool retval = false;
     if (is_fpga(addr)) { // addressed with FPGA_...
         //cout << "UniboardMap::write fpga point [" << addr << "]" << endl;
-        retval = point(termout, 'W', addr, data, cm, nvalues);
+        retval = point(termout, 'W', addr, data, nvalues);
     }
     return retval;
 }
diff --git a/src/map.h b/src/map.h
index a87d339e..051be34c 100644
--- a/src/map.h
+++ b/src/map.h
@@ -54,7 +54,7 @@ bool is_initialized(void) { return initialized; }
 bool init(TermOutput& termout);
 
 bool write(TermOutput& termout, const std::string addr,
-           const unsigned int *data, CMData& cm, const int nvalues);
+           const unsigned int *data, const int nvalues);
 
 bool read(TermOutput& termout, const std::string addr,
           const int nvalues);
diff --git a/src/node.cpp b/src/node.cpp
index 1a108919..bc8c1fbb 100644
--- a/src/node.cpp
+++ b/src/node.cpp
@@ -169,7 +169,7 @@ void Node::worker()
                 sz = sizeof(uint16_t);
             } break;
             case REG_FORMAT_STRING: {
-                sz = sizeof(char);
+                sz = sizeof(char) * SIZE1STRING;
             } break;
             case REG_FORMAT_BOOLEAN: {
                 sz = sizeof(bool);
@@ -292,7 +292,11 @@ bool Node::exec_cmd(const char cmd, const string relative_addr,
     p.nvalues = nvalues;
     p.format = format;
     if (cmd == 'W') {
-        memcpy((void *)p.data, (void *)data, nvalues);
+        if (format == REG_FORMAT_STRING) {
+            memcpy((void *)p.data, (void *)data, nvalues*SIZE1STRING);
+        } else {
+            memcpy((void *)p.data, (void *)data, nvalues*sizeof(unsigned int));
+        }
         // cout << " p.relative_addr=" << p.relative_addr << endl;
         // cout << " p.nvalues=" << p.nvalues << endl;
         // cout << " p.format=" << p.format << endl;
@@ -356,7 +360,7 @@ bool Node::exec_reply(TermOutput& termout)
             sz = sizeof(bool);
         } break;
         case REG_FORMAT_STRING: {
-            sz = sizeof(char);
+            sz = sizeof(char) * SIZE1STRING;
         } break;
         default: {
             // cout << "node-r400, Not supported datatype (" << r->datatype << ")" << endl;
diff --git a/src/opcua/ua_server.cpp b/src/opcua/ua_server.cpp
index 2b193a82..a3192b0f 100644
--- a/src/opcua/ua_server.cpp
+++ b/src/opcua/ua_server.cpp
@@ -414,19 +414,26 @@ static UA_StatusCode ua_write_DataSource(UA_Server *server,
 
         if (data->hasValue && data->value.arrayLength > 0) {
             //data.value is a UA_Variant
-            uint32_t *data_sdp = new uint32_t[data->value.arrayLength*2];
-            CMData cm(data->value.arrayLength);
-            cm.clear();
+            uint type = ntype.identifier.numeric - 1;
+            uint32_t *data_sdp;
+            uint32_t sz;
+            if ((type == UA_TYPES_DOUBLE) || (type == UA_TYPES_INT64) || (type == UA_TYPES_UINT64)) {
+                sz = data->value.arrayLength * 2;
+            } else if (type == UA_TYPES_STRING) {
+                sz = data->value.arrayLength * (SIZE1STRING / 4);
+            } else {
+                sz = data->value.arrayLength;
+            }
+            data_sdp = new uint32_t[sz];
+            memset((void *)data_sdp, 0, sizeof(uint32_t)*sz);
 
             switch (ntype.identifier.numeric - 1) {
                 case UA_TYPES_STRING: {
-                    cm.setFormat(FORMAT_STRING);
                     UA_String *dptr = (UA_String *)data->value.data;
                     UA_String str_data;
                     for (int i=0; i<(int)data->value.arrayLength; i++){
                         str_data = dptr[i];
-                        cm.clearStr(i);
-                        memcpy((void *)cm.getStrPtr(i), (void *)str_data.data, str_data.length);
+                        memcpy((void *)&(data_sdp[i*(SIZE1STRING/4)]), (void *)str_data.data, str_data.length);
                     }
                     retval = true;
                 } break;
@@ -496,7 +503,7 @@ static UA_StatusCode ua_write_DataSource(UA_Server *server,
             if (retval) {
                 TermOutput termout;
                 try {
-                    SD.unb->write(termout, regname, data_sdp, cm, data->value.arrayLength);
+                    SD.unb->write(termout, regname, data_sdp, data->value.arrayLength);
                 } catch (runtime_error& e) {
                     cerr << "ua_write_DataSource error: " << e.what() << endl;
                     retval = false;
diff --git a/src/periph/fpga.cpp b/src/periph/fpga.cpp
index 6c890648..1a8741dc 100644
--- a/src/periph/fpga.cpp
+++ b/src/periph/fpga.cpp
@@ -117,6 +117,12 @@ Periph_fpga::Periph_fpga(string ipaddr, string expected_design_name, uint expect
     registerMap->add_register("fpga/sst_offload_hdr_ip_destination_address", "-", 1, 1, "RW", REG_FORMAT_STRING);
     registerMap->add_register("fpga/sst_offload_hdr_udp_destination_port",   "-", 1, 1, "RW", REG_FORMAT_UINT16);
 
+    registerMap->add_register("fpga/bst_offload_enable",                     "-", 1, 2, "RW", REG_FORMAT_BOOLEAN);
+    registerMap->add_register("fpga/bst_offload_hdr_eth_destination_mac",    "-", 1, 2, "RW", REG_FORMAT_STRING);
+    registerMap->add_register("fpga/bst_offload_hdr_ip_destination_address", "-", 1, 2, "RW", REG_FORMAT_STRING);
+    registerMap->add_register("fpga/bst_offload_hdr_udp_destination_port",   "-", 1, 2, "RW", REG_FORMAT_UINT16);
+    registerMap->add_register("fpga/bst_offload_nof_beamlets_per_packet",    "-", 1, 2, "RW", REG_FORMAT_UINT32);
+
     registerMap->add_register("fpga/sdp_info_station_id",                    "-", 1, 1, "RW", REG_FORMAT_UINT32);
     registerMap->add_register("fpga/sdp_info_observation_id",                "-", 1, 1, "RW", REG_FORMAT_UINT32);
     registerMap->add_register("fpga/sdp_info_nyquist_sampling_zone_index",   "-", 1, 1, "RW", REG_FORMAT_UINT32);
@@ -129,18 +135,18 @@ Periph_fpga::Periph_fpga(string ipaddr, string expected_design_name, uint expect
     registerMap->add_register("fpga/wg_amplitude",                           "-", 1, 12, "RW", REG_FORMAT_DOUBLE);
     registerMap->add_register("fpga/wg_phase",                               "-", 1, 12, "RW", REG_FORMAT_DOUBLE);
     registerMap->add_register("fpga/wg_frequency",                           "-", 1, 12, "RW", REG_FORMAT_DOUBLE);
-    
+
     registerMap->add_register("fpga/bsn_monitor_input_sync_timeout",         "-", 1, 1, "RO", REG_FORMAT_BOOLEAN);
     registerMap->add_register("fpga/bsn_monitor_input_bsn",                  "-", 1, 1, "RO", REG_FORMAT_INT64);
     registerMap->add_register("fpga/bsn_monitor_input_nof_packets",          "-", 1, 1, "RO", REG_FORMAT_INT32);
     registerMap->add_register("fpga/bsn_monitor_input_nof_valid",            "-", 1, 1, "RO", REG_FORMAT_INT32);
     registerMap->add_register("fpga/bsn_monitor_input_nof_err",              "-", 1, 1, "RO", REG_FORMAT_INT32);
-    
+
     registerMap->add_register("fpga/jesd204b_csr_rbd_count",                 "-", 1, 12, "RO", REG_FORMAT_UINT32);
     registerMap->add_register("fpga/jesd204b_csr_dev_syncn",                 "-", 1, 12, "RO", REG_FORMAT_UINT32);
     registerMap->add_register("fpga/jesd204b_csr_rx_err0",                   "-", 1, 12, "RO", REG_FORMAT_UINT32);
     registerMap->add_register("fpga/jesd204b_csr_rx_err1",                   "-", 1, 12, "RO", REG_FORMAT_UINT32);
-    
+
     registerMap->add_register("fpga/signal_input_samples_delay",             "-", 1, 12, "RW", REG_FORMAT_UINT32);
 
     registerMap->add_register("fpga/subband_weights",                        "-", 1, 12*512, "RW", REG_FORMAT_UINT32);
@@ -419,6 +425,21 @@ bool Periph_fpga::read(TermOutput& termout, const string addr,
         else if (addr == "fpga/sst_offload_hdr_udp_destination_port") {
             retval = read_sst_offload_hdr_udp_destination_port(termout, format);
         }
+        else if (addr == "fpga/bst_offload_enable") {
+            retval = read_bst_offload_enable(termout, format);
+        }
+        else if (addr == "fpga/bst_offload_hdr_eth_destination_mac") {
+            retval = read_bst_offload_hdr_eth_destination_mac(termout, format);
+        }
+        else if (addr == "fpga/bst_offload_hdr_ip_destination_address") {
+            retval = read_bst_offload_hdr_ip_destination_address(termout, format);
+        }
+        else if (addr == "fpga/bst_offload_hdr_udp_destination_port") {
+            retval = read_bst_offload_hdr_udp_destination_port(termout, format);
+        }
+        else if (addr == "fpga/bst_offload_nof_beamlets_per_packet") {
+            retval = read_bst_offload_nof_beamlets_per_packet(termout, format);
+        }
         else if (addr == "fpga/processing_enable") {
             retval = read_processing_enable(termout, format);
         }
@@ -561,6 +582,21 @@ bool Periph_fpga::write(TermOutput& termout, const string addr, const string typ
         else if (addr == "fpga/sst_offload_hdr_udp_destination_port") {
             retval = write_sst_offload_hdr_udp_destination_port(data_ptr);
         }
+        else if (addr == "fpga/bst_offload_enable") {
+            retval = write_bst_offload_enable(data_ptr);
+        }
+        else if (addr == "fpga/bst_offload_hdr_eth_destination_mac") {
+            retval = write_bst_offload_hdr_eth_destination_mac(data);
+        }
+        else if (addr == "fpga/bst_offload_hdr_ip_destination_address") {
+            retval = write_bst_offload_hdr_ip_destination_address(data);
+        }
+        else if (addr == "fpga/bst_offload_hdr_udp_destination_port") {
+            retval = write_bst_offload_hdr_udp_destination_port(data_ptr);
+        }
+        else if (addr == "fpga/bst_offload_nof_beamlets_per_packet") {
+            retval = write_bst_offload_nof_beamlets_per_packet(data_ptr);
+        }
         else if (addr == "fpga/processing_enable") {
             retval = write_processing_enable(data_ptr);
         }
@@ -775,7 +811,7 @@ bool Periph_fpga::read_hardware_version(TermOutput& termout, int format)
     else {
         version = "Unknown";
     }
-    termout.nof_vals = version.size();
+    termout.nof_vals = 1;
     termout.datatype = format;
     strcpy(termout.val, version.c_str());
     return retval;
@@ -814,7 +850,7 @@ bool Periph_fpga::read_firmware_version(TermOutput& termout, int format)
             + "_"
             + revision + "_" + design_name;
 
-    termout.nof_vals = version.size();
+    termout.nof_vals = 1;
     termout.datatype = format;
     strcpy(termout.val, version.c_str());
     return retval;
@@ -842,7 +878,7 @@ bool Periph_fpga::read_fpga_temperature(TermOutput& termout, int format)
     // see the constants: https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_alttemp_sense.pdf
     // page 10
     temp = ((693. * (double)data[0]) / 1024.) - 265;
-    
+
     double *temp_ptr = (double *)termout.val;
     *temp_ptr = temp;
     termout.nof_vals = 1;
@@ -914,7 +950,7 @@ bool Periph_fpga::write_fpga_weights(const uint32_t *data)
             if (si >= nvalues) {
                 break;
             }
-            ds = *ptr++; 
+            ds = *ptr++;
             si++;
             if (si >= nvalues) {
                 break;
@@ -938,7 +974,7 @@ bool Periph_fpga::read_sst_offload_weighted_subbands(TermOutput& termout, int fo
     memset((void *)data, 0, sizeof(data));
     retval = Read("mm/0/REG_DP_SELECTOR/0/input_select", data);
 
-    bool select = (bool)data[0];
+    bool select = !(bool)data[0];
 
     bool *_ptr = (bool *)termout.val;
     *_ptr = select;
@@ -949,7 +985,11 @@ bool Periph_fpga::read_sst_offload_weighted_subbands(TermOutput& termout, int fo
 
 bool Periph_fpga::write_sst_offload_weighted_subbands(uint32_t *data)
 {
-    bool retval = Write("mm/0/REG_DP_SELECTOR/0/input_select", data);
+    uint32_t *reg = new uint32_t[2];
+    reg[0] = 0;
+    if (data[0] == 0) reg[0] = 1;
+    bool retval = Write("mm/0/REG_DP_SELECTOR/0/input_select", reg);
+    delete[] reg;
     return retval;
 }
 
@@ -996,7 +1036,7 @@ bool Periph_fpga::read_sst_offload_hdr_eth_destination_mac(TermOutput& termout,
 
     string mac_str = mac_ss.str();
     strcpy(termout.val, mac_str.c_str());
-    termout.nof_vals = mac_str.size();
+    termout.nof_vals = 1;
     termout.datatype = format;
     return retval;
 }
@@ -1038,7 +1078,7 @@ bool Periph_fpga::read_sst_offload_hdr_ip_destination_address(TermOutput& termou
 
     string ip_str = ip_ss.str();
     strcpy(termout.val, ip_str.c_str());
-    termout.nof_vals = ip_str.size();
+    termout.nof_vals = 1;
     termout.datatype = format;
     return retval;
 }
@@ -1078,9 +1118,9 @@ bool Periph_fpga::read_sst_offload_hdr_udp_destination_port(TermOutput& termout,
     uint32_t data[20];
     memset((void *)data, 0, sizeof(data));
     retval = Read("mm/0/REG_STAT_HDR_DAT_SST/0/udp_destination_port", data);
-    int port = (int)data[0];
+    uint16_t port = (uint16_t)data[0];
 
-    int *_ptr = (int *)termout.val;
+    uint16_t *_ptr = (uint16_t *)termout.val;
     *_ptr = port;
 
     termout.nof_vals = 1;
@@ -1093,6 +1133,249 @@ bool Periph_fpga::write_sst_offload_hdr_udp_destination_port(uint32_t *data)
     return Write("mm/0/REG_STAT_HDR_DAT_SST/0/udp_destination_port", data);
 }
 
+bool Periph_fpga::read_bst_offload_enable(TermOutput& termout, int format)
+{
+    bool retval = true;
+    string regname;
+    uint32_t data[20];
+    // bool select;
+    bool *_ptr = (bool *)termout.val;
+    for (uint32_t i=0; i<C_N_beamsets; i++) {
+        memset((void *)data, 0, sizeof(data));
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/enable";
+        if (Read(regname, data) == false) {
+           retval = false;
+        }
+        bool select = (bool)data[0];
+        *_ptr = select;
+        _ptr++;
+    }
+    termout.nof_vals = 2;
+    termout.datatype = format;
+    return retval;
+}
+
+bool Periph_fpga::write_bst_offload_enable(uint32_t *data)
+{
+    bool retval = true;
+    string regname;
+    for (uint32_t i=0; i<C_N_beamsets; i++) {
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/enable";
+        if (Write(regname, &data[i]) == false) {
+            retval = false;
+        }
+    }
+    return retval;
+}
+
+
+bool Periph_fpga::read_bst_offload_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<C_N_beamsets; i++) {
+        memset((void *)data, 0, sizeof(data));
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/eth_destination_mac";
+        if (Read(regname, data) == false) {
+            retval = false;
+        }
+        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 = C_N_beamsets;
+    termout.datatype = format;
+    return retval;
+}
+
+bool Periph_fpga::write_bst_offload_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<C_N_beamsets; i++) {
+        ss.clear();
+        ss.str("");
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/eth_destination_mac";
+        ds = &data[i*SIZE1STRING];
+        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_sst_offload_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;
+        if (Write(regname, mac) == false) {
+            retval = false;
+        }
+    }
+    return retval;
+}
+
+bool Periph_fpga::read_bst_offload_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<C_N_beamsets; i++) {
+        memset((void *)data, 0, sizeof(data));
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/ip_destination_address";
+        if (Read(regname, data) == false) {
+            retval = false;
+        }
+        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 = C_N_beamsets;
+    termout.datatype = format;
+    return retval;
+}
+
+bool Periph_fpga::write_bst_offload_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<C_N_beamsets; i++) {
+        ss.clear();
+        ss.str("");
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/ip_destination_address";
+        // cout << "write_ip=[" << ds << "]" << endl;
+        ds = &data[i*SIZE1STRING];
+        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_sst_offload_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::read_bst_offload_hdr_udp_destination_port(TermOutput& termout, int format)
+{
+    bool retval = true;
+    string regname;
+
+    uint32_t data[20];
+    // int port;
+    uint16_t *_ptr = (uint16_t *)termout.val;
+    for (uint32_t i=0; i<C_N_beamsets; i++) {
+        memset((void *)data, 0, sizeof(data));
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/udp_destination_port";
+        if (Read(regname, data) == false) {
+            retval = false;
+        }
+        // cout << "read_bst_offload_hdr_udp_destination_port " << i << "=" << data[0] << endl;
+        uint16_t port = (uint16_t)data[0];
+        *_ptr = port;
+        _ptr++;
+    }
+    termout.nof_vals = C_N_beamsets;
+    termout.datatype = format;
+    return retval;
+}
+
+bool Periph_fpga::write_bst_offload_hdr_udp_destination_port(uint32_t *data)
+{
+    bool retval = true;
+    string regname;
+    for (uint32_t i=0; i<C_N_beamsets; i++) {
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/udp_destination_port";
+        if (Write(regname, &data[i]) == false) {
+            retval = false;
+        }
+    }
+    return retval;
+}
+
+bool Periph_fpga::read_bst_offload_nof_beamlets_per_packet(TermOutput& termout, int format)
+{
+    bool retval = true;
+    string regname;
+
+    uint32_t data[20];
+    int *_ptr = (int *)termout.val;
+    for (uint32_t i=0; i<C_N_beamsets; i++) {
+        memset((void *)data, 0, sizeof(data));
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/TODO";
+        if (Read(regname, data) == false) {
+            retval = false;
+        }
+        int packets = (int)data[i];
+        *_ptr = packets;
+        _ptr++;
+    }
+    termout.nof_vals = C_N_beamsets;
+    termout.datatype = format;
+    return retval;
+}
+
+bool Periph_fpga::write_bst_offload_nof_beamlets_per_packet(uint32_t *data)
+{
+    bool retval = true;
+    string regname;
+    for (uint32_t i=0; i<C_N_beamsets; i++) {
+        regname = "mm/" + to_string(i) + "/REG_STAT_HDR_DAT_BST/0/TODO";
+        if (Write(regname, &data[i]) == false) {
+            retval = false;
+        }
+    }
+    return retval;
+}
 
 bool Periph_fpga::read_processing_enable(TermOutput& termout, int format)
 {
@@ -1512,7 +1795,7 @@ bool Periph_fpga::read_wg_frequency(TermOutput& termout, int format) {
 bool Periph_fpga::write_wg_frequency(uint32_t *data) {
     bool retval = true;
     uint32_t *reg = new uint32_t[2];
-    
+
     double freq, intpart;
     string regname;
     double *_ptr = (double *)data;
diff --git a/src/periph/fpga.h b/src/periph/fpga.h
index 7d743148..984aad2b 100644
--- a/src/periph/fpga.h
+++ b/src/periph/fpga.h
@@ -105,19 +105,26 @@ private:
 
   bool read_sst_offload_weighted_subbands(TermOutput& termout, int format);
   bool write_sst_offload_weighted_subbands(uint32_t *data);
-
   bool read_sst_offload_enable(TermOutput& termout, int format);
   bool write_sst_offload_enable(uint32_t *data);
-
   bool read_sst_offload_hdr_eth_destination_mac(TermOutput& termout, int format);
   bool write_sst_offload_hdr_eth_destination_mac(const char *data);
-
   bool read_sst_offload_hdr_ip_destination_address(TermOutput& termout, int format);
   bool write_sst_offload_hdr_ip_destination_address(const char *data);
-
   bool read_sst_offload_hdr_udp_destination_port(TermOutput& termout, int format);
   bool write_sst_offload_hdr_udp_destination_port(uint32_t *data);
 
+  bool read_bst_offload_enable(TermOutput& termout, int format);
+  bool write_bst_offload_enable(uint32_t *data);
+  bool read_bst_offload_hdr_eth_destination_mac(TermOutput& termout, int format);
+  bool write_bst_offload_hdr_eth_destination_mac(const char *data);
+  bool read_bst_offload_hdr_ip_destination_address(TermOutput& termout, int format);
+  bool write_bst_offload_hdr_ip_destination_address(const char *data);
+  bool read_bst_offload_hdr_udp_destination_port(TermOutput& termout, int format);
+  bool write_bst_offload_hdr_udp_destination_port(uint32_t *data);
+  bool read_bst_offload_nof_beamlets_per_packet(TermOutput& termout, int format);
+  bool write_bst_offload_nof_beamlets_per_packet(uint32_t *data);
+
   bool read_processing_enable(TermOutput& termout, int format);
   bool write_processing_enable(uint32_t *data);
 
diff --git a/src/tools/mmap.cpp b/src/tools/mmap.cpp
index b1a5a0dc..913f5462 100644
--- a/src/tools/mmap.cpp
+++ b/src/tools/mmap.cpp
@@ -55,6 +55,7 @@ typedef struct {
 void mmap_add_register(CMMap& regmap, mm_info_t mm_info)
 {
     bool update;
+    uint32_t base_addr = mm_info.base_addr;
     uint32_t addr;
     string full_name;
     for (uint i=0; i<mm_info.n_peripherals; i++) {
@@ -63,11 +64,10 @@ void mmap_add_register(CMMap& regmap, mm_info_t mm_info)
             full_name = "mm/" + to_string(i) + "/" + mm_info.port_name + "/" + to_string(j) + "/" + mm_info.field_name;
 
             if (regmap.find_register(full_name)) {
-                mm_info.base_addr = regmap.getBaseAddr(full_name);
-                mm_info.span += regmap.getSpan(full_name);
+                // mm_info.base_addr = regmap.getBaseAddr(full_name);
                 update = true;
             }
-            addr = mm_info.base_addr + (i * mm_info.peripheral_span) + (j * mm_info.mm_port_span);
+            addr = base_addr + (i * mm_info.peripheral_span) + (j * mm_info.mm_port_span);
 
             if (update) {
                 regmap.update_register(full_name,
@@ -114,16 +114,18 @@ CMMap mmap_to_regmap(istringstream& iss)
     char line[250];
     string val_str;
     bool same_mask;
+    bool same_field_name;
     // char sep;
 
     iss.getline(line, sizeof(line));
     iss.getline(line, sizeof(line));
     while (iss.getline(line, sizeof(line))) {
         same_mask = false;
+        same_field_name = false;
         mm_info = last_mm_info;
         stringstream strs(line);
 
-        strs >> val_str;
+        strs >> val_str;  // get port name
         if (val_str != "-") {
             mm_info.port_name = val_str;
             mm_info.peripheral_span = 1;
@@ -132,45 +134,49 @@ CMMap mmap_to_regmap(istringstream& iss)
             mm_info.n_ports = 1;
         }
 
-        strs >> val_str;
+        strs >> val_str;  // get n_peripherals
         // mm_info.n_peripherals = 1;
         if (val_str != "-") {
             mm_info.n_peripherals = stoi(val_str);
         }
 
-        strs >> val_str;
+        strs >> val_str;  // get n_ports
         // mm_info.n_ports = 1;
         if (val_str != "-") {
             mm_info.n_ports = stoi(val_str);
         }
 
-        strs >> val_str;
+        strs >> val_str;  // get port_type
         if (val_str != "-") {
             mm_info.port_type = val_str;
         }
 
-        strs >> val_str;
+        strs >> val_str;  // get field_name
         if (val_str != "-") {
             mm_info.field_name = val_str;
+            mm_info.span = 0;
         }
         else {
             same_mask = true;
+            same_field_name = true;
         }
 
-        strs >> hex >> start_addr44; // in dword addresses
-        mm_info.base_addr = (uint32_t)start_addr44;
+        strs >> hex >> start_addr44; // get start_address in dword addresses
+        if (!same_field_name) {
+            mm_info.base_addr = (uint32_t)start_addr44;
+        }
 
-        strs >> val_str;
+        strs >> val_str;  // get n_fields
         if (val_str != "-") {
             mm_info.n_fields = stoi(val_str);
         }
 
-        strs >> val_str;
+        strs >> val_str;  // get acces_mode
         if (val_str != "-") {
             mm_info.acces_mode = val_str;
         }
 
-        strs >> val_str;
+        strs >> val_str;  // get radix
         if (val_str != "-") {
             mm_info.radix = val_str;
         }
@@ -179,7 +185,7 @@ CMMap mmap_to_regmap(istringstream& iss)
         // strs >> mm_mask_hi;
         // strs >> sep;
         // strs >> mm_mask_lo;
-        strs >> val_str;
+        strs >> val_str;  // get mm_mask hi/lo
         sscanf(val_str.c_str(), "%d:%d", &mm_mask_hi, &mm_mask_lo);
         mask = 0;
         for (int i=mm_mask_lo; i<=mm_mask_hi; i++) {
@@ -207,7 +213,8 @@ CMMap mmap_to_regmap(istringstream& iss)
         //     mm_info.user_mask = mask;
         //     mm_info.span = (uint)(((user_mask_hi - user_mask_lo + 1) * mm_info.n_fields) / (mm_mask_hi - mm_mask_lo + 1));
         // }
-        strs >> val_str;
+        strs >> val_str;  // get user_mask hi/lo
+        uint32_t span;
         if (val_str != "-") {
             sscanf(val_str.c_str(), "%d:%d", &user_mask_hi, &user_mask_lo);
             mask = 0;
@@ -215,21 +222,23 @@ CMMap mmap_to_regmap(istringstream& iss)
                 mask |= (1<<i);
             }
             mm_info.user_mask = mask;
-            mm_info.span = (uint)(((user_mask_hi - user_mask_lo + 1) * mm_info.n_fields) / (mm_mask_hi - mm_mask_lo + 1));
+            span = (uint)(((user_mask_hi - user_mask_lo + 1) * mm_info.n_fields) / (mm_mask_hi - mm_mask_lo + 1));
         }
         else {
             mm_info.user_mask = mm_info.mm_mask;
-            mm_info.span = mm_info.n_fields;
+            span = mm_info.n_fields;
         }
+        mm_info.span += span;
+
 
-        strs >> val_str;
+        strs >> val_str;  // get peripheral_span
         if (val_str != "-") {
             if (mm_info.n_peripherals > 1 || mm_info.n_ports > 1) {
                 mm_info.peripheral_span = stoi(val_str);
             }
         }
 
-        strs >> val_str;
+        strs >> val_str;  // get mm_port_span
         if (val_str != "-") {
             if (mm_info.n_peripherals > 1 || mm_info.n_ports > 1) {
                 mm_info.mm_port_span = stoi(val_str);
diff --git a/src/tools/util.h b/src/tools/util.h
index a2faf0f0..8aad1f88 100644
--- a/src/tools/util.h
+++ b/src/tools/util.h
@@ -58,55 +58,6 @@ struct StrData {
     char val[MAX_VAL_SIZE];
 };
 
-// for transport of Control and Monitor data
-class CMData {
-public:
-    uint n_vals = 1;
-    uint dataformat = FORMAT_UNKNOWN;
-    StrData *strdata = NULL; 
-
-    CMData(uint nvals=1) {
-        n_vals = nvals;
-        strdata = new StrData[n_vals];  
-    };
-
-    ~CMData() {
-        if (strdata) delete[] strdata;
-    };
-
-    void setFormat(uint format) {
-        dataformat = format;
-    }
-
-    uint getFormat() {
-        return dataformat;
-    }
-
-    void clear(void) {
-      //n_vals = 0;
-      //datatype = 0;
-      for (uint i=0; i<n_vals; i++){
-        clearStr(i);
-      }
-    }
-
-    void clearStr(uint val_nr) {
-        std::memset((void *)strdata[val_nr].val, 0, MAX_VAL_SIZE);
-    }
-    
-    char *getStrPtr(uint val_nr) {
-       return strdata[val_nr].val;
-    }
-
-    uint getStrLen(uint val_nr) {
-       return strlen(strdata[val_nr].val);
-    }
-
-    std::string getStr(uint val_nr) {
-       return std::string(strdata[val_nr].val);
-    }
-};
-
 
 class TermOutput {
 public:
-- 
GitLab