Select Git revision
Forked from
LOFAR2.0 / sdptr
Source project has a limited visibility.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
fpga.cpp 18.30 KiB
/* *************************************************************************
* Copyright 2020
* ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
* P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* *********************************************************************** */
/* *************************************************************************
* Author:
* . Leon Hiemstra
* . Pieter Donker
* Purpose:
* . opc-ua to ucp translator
* Description:
* . class with fpga registers available for opc-ua server
* *********************************************************************** */
#ifndef _REENTRANT
#error ACK! You need to compile with _REENTRANT defined since this uses threads
#endif
#include <cstdio>
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <exception>
#include "constants.h"
#include "fpga.h"
#include "tools/parse.h"
using namespace std;
// Everything addressed with FPGA_...
extern int debug;
Fpga::Fpga(list<class Node*>& nodelist)
{
FPGA = nodelist;
pointMap = new CPointMap();
// Add points:
vector<int> nodes = get_all_nodes();
pointMap->add_register("FPGA_mask_R", "fpga/enable_mask", nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_mask_RW", "fpga/enable_mask", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_status_R", "fpga/status", nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_temp_R", "fpga/temp", nodes.size(), 1, "RO", REG_FORMAT_DOUBLE, 1);
pointMap->add_register("FPGA_version_R", "fpga/name", nodes.size(), 1, "RO", REG_FORMAT_STRING, 1);
pointMap->add_register("FPGA_firmware_version_R", "fpga/firmware_version", nodes.size(), 1, "RO", REG_FORMAT_STRING, 1);
pointMap->add_register("FPGA_hardware_version_R", "fpga/hardware_version", nodes.size(), 1, "RO", REG_FORMAT_STRING, 1);
pointMap->add_register("FPGA_sst_offload_selector_R", "fpga/sst_offload_selector", nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_sst_offload_selector_RW", "fpga/sst_offload_selector", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_sst_offload_enable_R", "fpga/sst_offload_enable", nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_sst_offload_enable_RW", "fpga/sst_offload_enable", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_sst_offload_hdr_eth_destination_mac_R", "fpga/sst_offload_hdr_eth_destination_mac", nodes.size(), 1, "RO", REG_FORMAT_STRING, 1);
pointMap->add_register("FPGA_sst_offload_hdr_eth_destination_mac_RW", "fpga/sst_offload_hdr_eth_destination_mac", nodes.size(), 1, "RW", REG_FORMAT_STRING, 1);
pointMap->add_register("FPGA_sst_offload_hdr_ip_destination_address_R", "fpga/sst_offload_hdr_ip_destination_address", nodes.size(), 1, "RO", REG_FORMAT_STRING, 1);
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, 1);
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, 1);
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, 1);
pointMap->add_register("FPGA_processing_enable_R", "fpga/processing_enable", nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_processing_enable_RW", "fpga/processing_enable", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_sdp_info_station_id_R", "fpga/sdp_info_station_id", nodes.size(), 1, "RO", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_sdp_info_station_id_RW", "fpga/sdp_info_station_id", nodes.size(), 1, "RW", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_sdp_info_observation_id_R", "fpga/sdp_info_observation_id", nodes.size(), 1, "RO", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_sdp_info_observation_id_RW", "fpga/sdp_info_observation_id", nodes.size(), 1, "RW", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_sdp_info_nyquist_sampling_zone_index_R", "fpga/sdp_info_nyquist_sampling_zone_index", nodes.size(), 1, "RO", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_sdp_info_nyquist_sampling_zone_index_RW", "fpga/sdp_info_nyquist_sampling_zone_index", nodes.size(), 1, "RW", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_sdp_info_antenna_band_index_R", "fpga/sdp_info_antenna_band_index", nodes.size(), 1, "RO", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_sdp_info_f_adc_R", "fpga/sdp_info_f_adc", nodes.size(), 1, "RO", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_sdp_info_fsub_type_R", "fpga/sdp_info_fsub_type", nodes.size(), 1, "RO", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_sdp_info_block_period_R", "fpga/sdp_info_block_period", nodes.size(), 1, "RO", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_wg_enable_R", "fpga/wg_enable", nodes.size(), C_S_pn, "RO", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_wg_enable_RW", "fpga/wg_enable", nodes.size(), C_S_pn, "RW", REG_FORMAT_BOOLEAN, 1);
pointMap->add_register("FPGA_wg_amplitude_R", "fpga/wg_amplitude", nodes.size(), C_S_pn, "RO", REG_FORMAT_DOUBLE, 1);
pointMap->add_register("FPGA_wg_amplitude_RW", "fpga/wg_amplitude", nodes.size(), C_S_pn, "RW", REG_FORMAT_DOUBLE, 1);
pointMap->add_register("FPGA_wg_phase_R", "fpga/wg_phase", nodes.size(), C_S_pn, "RO", REG_FORMAT_DOUBLE, 1);
pointMap->add_register("FPGA_wg_phase_RW", "fpga/wg_phase", nodes.size(), C_S_pn, "RW", REG_FORMAT_DOUBLE, 1);
pointMap->add_register("FPGA_wg_frequency_R", "fpga/wg_frequency", nodes.size(), C_S_pn, "RO", REG_FORMAT_DOUBLE, 1);
pointMap->add_register("FPGA_wg_frequency_RW", "fpga/wg_frequency", nodes.size(), C_S_pn, "RW", REG_FORMAT_DOUBLE, 1);
pointMap->add_register("FPGA_bsn_monitor_input_bsn_R", "fpga/bsn_monitor_input_bsn", nodes.size(), 1, "RO", REG_FORMAT_INT64, 1);
pointMap->add_register("FPGA_bsn_monitor_input_nof_packets_R", "fpga/bsn_monitor_input_nof_packets", nodes.size(), 1, "RO", REG_FORMAT_INT32, 1);
pointMap->add_register("FPGA_bsn_monitor_input_nof_valid_R", "fpga/bsn_monitor_input_nof_valid", nodes.size(), 1, "RO", REG_FORMAT_INT32, 1);
pointMap->add_register("FPGA_bsn_monitor_input_nof_err_R", "fpga/bsn_monitor_input_nof_err", nodes.size(), 1, "RO", REG_FORMAT_INT32, 1);
uint32_t scrap_span = 0;
uint32_t scrap_span_next = 0;
uint32_t scrap_span_prev = 0;
for (uint idx=0; idx<nodes.size(); idx++) {
auto node = select_node(nodes[idx]);
CPointMap *regmap = node->get_RegisterMap();
scrap_span_next = regmap->getDataSize("fpga/scrap");
if (scrap_span_next > scrap_span_prev) {
scrap_span = scrap_span_next;
}
scrap_span_prev = scrap_span_next;
}
cout << "scrap_span=" << scrap_span << endl;
pointMap->add_register("FPGA_scrap_R", "fpga/scrap", nodes.size(), scrap_span, "RO", REG_FORMAT_UINT32, 1);
pointMap->add_register("FPGA_scrap_RW", "fpga/scrap", nodes.size(), scrap_span, "RW", REG_FORMAT_UINT32, 1);
uint32_t weights_span = 0;
uint32_t weights_span_next = 0;
uint32_t weights_span_prev = 0;
for (uint idx=0; idx<nodes.size(); idx++) {
auto node = select_node(nodes[idx]);
CPointMap *regmap = node->get_RegisterMap();
weights_span_next = regmap->getDataSize("fpga/weights");
if (weights_span_next > weights_span_prev) {
weights_span = weights_span_next;
}
weights_span_prev = weights_span_next;
}
cout << "weights_span=" << weights_span << endl;
pointMap->add_register("FPGA_weights_R", "fpga/weights", nodes.size(), weights_span, "RO", REG_FORMAT_INT16, 1);
pointMap->add_register("FPGA_weights_RW", "fpga/weights", nodes.size(), weights_span, "RW", REG_FORMAT_INT16, 1);
}
Fpga::~Fpga()
{
if (pointMap != NULL) {
delete pointMap;
}
}
Node * Fpga::select_node(const int nr)
{
for (auto node : FPGA) {
if (node->GetGlobalNr() == (uint)nr) {
return node;
}
}
throw runtime_error("select_node: not found");
}
vector<int> Fpga::get_all_nodes(void)
{
vector<int> nodes;
for (auto node : FPGA) {
nodes.push_back(node->GetGlobalNr());
}
return nodes;
}
vector<bool> Fpga::get_all_enabled_nodes(void)
{
vector<bool> enabled;
for (auto node : FPGA) {
enabled.push_back(node->GetEnabled());
}
return enabled;
}
uint Fpga::node_number(Node *node)
{
return (node->GetUniboardNr() * 4) + node->GetLocalNr();
}
CPointMap * Fpga::get_pointMap(void)
{
return pointMap;
}
bool Fpga::point(TermOutput& termout, const char cmd, const string addr,
const unsigned int *data, CMData& cm, const int nvalues)
{
bool ret, retval = false;
uint retcnt = 0;
termout.clear();
string relative_addr = pointMap->getRelativeName(addr);
string type = "fpga";
string instance = "";
try {
if (cmd == 'R') {
pointMap->getReadPermission(addr);
}
else if (cmd == 'W') {
pointMap->getWritePermission(addr);
}
} catch (exception& e) {
cerr << "Fpga::point: " << addr << " error: " << e.what() << endl;
return false;
}
int format = pointMap->getFormat(addr);
vector<int> nodes = get_all_nodes();
TermOutput termresults;
if (cmd == 'R') {
retval = true;
}
else if (cmd == 'W') {
if (nvalues < (int)pointMap->getDataSize(addr)) {
return false;
}
retval = true;
}
for (uint idx = 0; idx<nodes.size(); idx++) {
auto node = select_node(nodes[idx]);
// if (node->getEnabled() == false) { continue; }
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') {
didx = idx * nof_values;
}
if ((ret = node->exec_cmd(cmd, relative_addr, type, instance,
&data[didx], nof_values*sizeof(unsigned int), format))) {
retcnt++;
}
}
} catch (exception& e) {
cerr << e.what() << endl;
}
}
retval = (retcnt == nodes.size());
if (!retval) {
return false;
}
termout.nof_vals = pointMap->getNodesSize(addr) * pointMap->getDataSize(addr);
termout.datatype = pointMap->getFormat(addr);
for (uint idx=0; idx<nodes.size(); idx++) {
auto node = select_node(nodes[idx]);
ret = false;
termresults.clear();
try {
if ((ret = node->exec_reply(termresults))) {
retcnt++;
}
} catch (exception& e) {
cerr << e.what() << endl;
}
if (cmd == 'R') {
switch (termresults.datatype) {
case REG_FORMAT_BOOLEAN: {
bool *ptr_in = (bool *)termresults.val;
bool *ptr_out = (bool *)termout.val;
for (unsigned int i=0; i<termresults.nof_vals; i++) {
ptr_out[idx * termresults.nof_vals + i] = ptr_in[i];
}
} break;
case REG_FORMAT_INT64: {
int64_t *ptr_in = (int64_t *)termresults.val;
int64_t *ptr_out = (int64_t *)termout.val;
for (uint i=0; i<termresults.nof_vals; i++) {
ptr_out[idx * termresults.nof_vals + i] = ptr_in[i];
}
} break;
case REG_FORMAT_UINT64: {
uint64_t *ptr_in = (uint64_t *)termresults.val;
uint64_t *ptr_out = (uint64_t *)termout.val;
for (uint i=0; i<termresults.nof_vals; i++) {
ptr_out[idx * termresults.nof_vals + i] = ptr_in[i];
}
} break;
case REG_FORMAT_INT32: {
int32_t *ptr_in = (int32_t *)termresults.val;
int32_t *ptr_out = (int32_t *)termout.val;
for (uint i=0; i<termresults.nof_vals; i++) {
ptr_out[idx * termresults.nof_vals + i] = ptr_in[i];
}
} break;
case REG_FORMAT_UINT32: {
uint32_t *ptr_in = (uint32_t *)termresults.val;
uint32_t *ptr_out = (uint32_t *)termout.val;
for (uint i=0; i<termresults.nof_vals; i++) {
ptr_out[idx * termresults.nof_vals + i] = ptr_in[i];
}
} break;
case REG_FORMAT_INT16: {
int16_t *ptr_in = (int16_t *)termresults.val;
int16_t *ptr_out = (int16_t *)termout.val;
for (uint i=0; i<termresults.nof_vals; i++) {
ptr_out[idx * termresults.nof_vals + i] = ptr_in[i];
}
} break;
case REG_FORMAT_UINT16: {
uint16_t *ptr_in = (uint16_t *)termresults.val;
uint16_t *ptr_out = (uint16_t *)termout.val;
for (uint i=0; i<termresults.nof_vals; i++) {
ptr_out[idx * termresults.nof_vals + i] = ptr_in[i];
}
} break;
case REG_FORMAT_FLOAT: {
float *ptr_in = (float *)termresults.val;
float *ptr_out = (float *)termout.val;
for (unsigned int i=0; i<termresults.nof_vals; i++) {
ptr_out[idx * termresults.nof_vals + i] = ptr_in[i];
}
} break;
case REG_FORMAT_DOUBLE: {
double *ptr_in = (double *)termresults.val;
double *ptr_out = (double *)termout.val;
for (unsigned int i=0; i<termresults.nof_vals; i++) {
ptr_out[idx * termresults.nof_vals + i] = ptr_in[i];
}
} break;
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);
} break;
default: {
cout << "fpga-r320, Not supported datatype (" << termresults.datatype << " in " << addr << endl;
} break;
}
}
else if (cmd == 'W') {
// nothing
}
}
if (nodes.size() == 0) {
cerr << "no nodes";
retval = false;
}
return retval;
}
bool Fpga::is_fpga(const string addr)
{
bool retval = false;
stringstream strs(addr);
string token;
vector<string> tokens;
while (getline(strs, token, '_')) {
tokens.push_back(token);
}
if (tokens.size() > 1) {
if (tokens[0] == "FPGA") {
retval = true;
}
}
return retval;
}