Select Git revision
pkgdoc-howto.cfg
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
fpga.cpp 22.11 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_temp_R", "fpga/temp", nodes.size(), 1, "RO", REG_FORMAT_DOUBLE);
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);
pointMap->add_register("FPGA_sst_offload_enable_RW", "fpga/sst_offload_enable", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN);
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);
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);
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);
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_xst_subband_select_R", "fpga/xst_subband_select", nodes.size(), 1+C_N_crosslets_max, "RO", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_xst_subband_select_RW", "fpga/xst_subband_select", nodes.size(), 1+C_N_crosslets_max, "RW", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_xst_integration_interval_R", "fpga/xst_integration_interval", nodes.size(), 1, "RO", REG_FORMAT_DOUBLE);
pointMap->add_register("FPGA_xst_integration_interval_RW", "fpga/xst_integration_interval", nodes.size(), 1, "RW", REG_FORMAT_DOUBLE);
pointMap->add_register("FPGA_xst_processing_enable_R", "fpga/xst_processing_enable", nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN);
pointMap->add_register("FPGA_xst_processing_enable_RW", "fpga/xst_processing_enable", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN);
pointMap->add_register("FPGA_xst_offload_enable_R", "fpga/xst_offload_enable", nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN);
pointMap->add_register("FPGA_xst_offload_enable_RW", "fpga/xst_offload_enable", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN);
pointMap->add_register("FPGA_xst_offload_hdr_eth_destination_mac_R", "fpga/xst_offload_hdr_eth_destination_mac", nodes.size(), 1, "RO", REG_FORMAT_STRING);
pointMap->add_register("FPGA_xst_offload_hdr_eth_destination_mac_RW", "fpga/xst_offload_hdr_eth_destination_mac", nodes.size(), 1, "RW", REG_FORMAT_STRING);
pointMap->add_register("FPGA_xst_offload_hdr_ip_destination_address_R", "fpga/xst_offload_hdr_ip_destination_address", nodes.size(), 1, "RO", REG_FORMAT_STRING);
pointMap->add_register("FPGA_xst_offload_hdr_ip_destination_address_RW", "fpga/xst_offload_hdr_ip_destination_address", nodes.size(), 1, "RW", REG_FORMAT_STRING);
pointMap->add_register("FPGA_xst_offload_hdr_udp_destination_port_R", "fpga/xst_offload_hdr_udp_destination_port", nodes.size(), 1, "RO", REG_FORMAT_UINT16);
pointMap->add_register("FPGA_xst_offload_hdr_udp_destination_port_RW", "fpga/xst_offload_hdr_udp_destination_port", nodes.size(), 1, "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);
pointMap->add_register("FPGA_sdp_info_station_id_RW", "fpga/sdp_info_station_id", nodes.size(), 1, "RW", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_sdp_info_observation_id_R", "fpga/sdp_info_observation_id", nodes.size(), 1, "RO", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_sdp_info_observation_id_RW", "fpga/sdp_info_observation_id", nodes.size(), 1, "RW", REG_FORMAT_UINT32);
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);
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);
pointMap->add_register("FPGA_sdp_info_antenna_band_index_R", "fpga/sdp_info_antenna_band_index", nodes.size(), 1, "RO", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_sdp_info_f_adc_R", "fpga/sdp_info_f_adc", nodes.size(), 1, "RO", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_sdp_info_fsub_type_R", "fpga/sdp_info_fsub_type", nodes.size(), 1, "RO", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_sdp_info_block_period_R", "fpga/sdp_info_block_period", nodes.size(), 1, "RO", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_wg_enable_R", "fpga/wg_enable", nodes.size(), C_S_pn, "RO", REG_FORMAT_BOOLEAN);
pointMap->add_register("FPGA_wg_enable_RW", "fpga/wg_enable", nodes.size(), C_S_pn, "RW", REG_FORMAT_BOOLEAN);
pointMap->add_register("FPGA_wg_amplitude_R", "fpga/wg_amplitude", nodes.size(), C_S_pn, "RO", REG_FORMAT_DOUBLE);
pointMap->add_register("FPGA_wg_amplitude_RW", "fpga/wg_amplitude", nodes.size(), C_S_pn, "RW", REG_FORMAT_DOUBLE);
pointMap->add_register("FPGA_wg_phase_R", "fpga/wg_phase", nodes.size(), C_S_pn, "RO", REG_FORMAT_DOUBLE);
pointMap->add_register("FPGA_wg_phase_RW", "fpga/wg_phase", nodes.size(), C_S_pn, "RW", REG_FORMAT_DOUBLE);
pointMap->add_register("FPGA_wg_frequency_R", "fpga/wg_frequency", nodes.size(), C_S_pn, "RO", REG_FORMAT_DOUBLE);
pointMap->add_register("FPGA_wg_frequency_RW", "fpga/wg_frequency", nodes.size(), C_S_pn, "RW", REG_FORMAT_DOUBLE);
pointMap->add_register("FPGA_bsn_monitor_input_bsn_R", "fpga/bsn_monitor_input_bsn", nodes.size(), 1, "RO", REG_FORMAT_INT64);
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_rx_err0", nodes.size(), C_S_pn, "RO", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_jesd204b_rx_err1_R", "fpga/jesd204b_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);
pointMap->add_register("FPGA_scrap_R", "fpga/scrap", nodes.size(), C_N_scrap, "RO", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_scrap_RW", "fpga/scrap", nodes.size(), C_N_scrap, "RW", REG_FORMAT_UINT32);
pointMap->add_register("FPGA_weights_R", "fpga/weights", nodes.size(), C_S_pn*C_N_beamlets, "RO", REG_FORMAT_INT16);
pointMap->add_register("FPGA_weights_RW", "fpga/weights", nodes.size(), C_S_pn*C_N_beamlets, "RW", REG_FORMAT_INT16);
}
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->isEnabled());
}
return enabled;
}
vector<bool> Fpga::get_all_masked_nodes(void)
{
vector<bool> masked;
for (auto node : FPGA) {
masked.push_back(node->isMasked());
}
return masked;
}
vector<bool> Fpga::get_all_offline_nodes(void)
{
vector<bool> online;
for (auto node : FPGA) {
online.push_back(!node->isOnline());
}
return online;
}
void Fpga::set_all_masked_nodes(std::vector<bool> masked)
{
vector<int> nodes = get_all_nodes();
for (uint idx = 0; idx<nodes.size(); idx++) {
auto node = select_node(nodes[idx]);
node->setMasked(masked[idx]);
}
}
vector<uint32_t> Fpga::get_all_pps_offset_cnt(void)
{
vector<uint32_t> pps_offset_cnt;
for (auto node : FPGA) {
pps_offset_cnt.push_back(node->ppsOffsetCnt());
}
return pps_offset_cnt;
}
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 char *data, const int nvalues)
{
bool ret, retval = false;
uint mask_cnt = 0;
uint exec_cnt = 0;
uint reply_cnt = 0;
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);
int nof_values = pointMap->getDataSize(addr);
vector<int> nodes = get_all_nodes();
TermOutput termresults;
if (cmd == 'R') {
retval = true;
}
else if (cmd == 'W') {
if (nvalues < nof_values) {
return false;
}
retval = true;
}
for (uint idx = 0; idx<nodes.size(); idx++) {
mask_cnt++;
auto node = select_node(nodes[idx]);
// if (node->getEnabled() == false) { continue; }
ret = false;
try {
uint didx = 0;
if (cmd == 'W') {
didx = idx * nof_values * reg_format_size_in_bytes(format);
}
if ((ret = node->exec_cmd(cmd, relative_addr, type, instance,
&data[didx], nof_values, format))) {
retcnt++;
exec_cnt++;
}
} 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++;
reply_cnt++;
}
} 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 * 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;
} 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;
}