Skip to content
Snippets Groups Projects
Select Git revision
  • 023552b5e0d25707013869830a65669184103014
  • master default protected
  • fix-64-bit
  • L2SDP-261
  • 2021-04-14T14.09.01_sdptr
  • 2021-04-14T13.43.34_sdptr
6 results

fpga.cpp

Blame
  • Forked from LOFAR2.0 / sdptr
    1301 commits behind the upstream repository.
    donker's avatar
    L2SDP-251: processed review comment
    Pieter Donker authored
    023552b5
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    fpga.cpp 11.43 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 "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 RegisterMap();
    
        // Add points:
        vector<int> nodes = get_all_nodes();
    
        pointMap->add_register("fpga_mask_RW",            0, nodes.size(), 0xffffffff, 0, "RW", "COMP", 0, REG_FORMAT_BOOLEAN);
        pointMap->add_register("fpga_status_R",           0, nodes.size(), 0xffffffff, 0, "RO", "COMP", 0, REG_FORMAT_BOOLEAN);
        pointMap->add_register("fpga_temp_R",             0, nodes.size(), 0xffffffff, 0, "RO", "COMP", 0, REG_FORMAT_FLOAT);
        pointMap->add_register("fpga_version_R",          0, nodes.size(), 0xffffffff, 0, "RO", "COMP", 0, REG_FORMAT_STRING);
        pointMap->add_register("fpga_firmware_version_R", 0, nodes.size(), 0xffffffff, 0, "RO", "COMP", 0, REG_FORMAT_STRING);
        pointMap->add_register("fpga_hardware_version_R", 0, nodes.size(), 0xffffffff, 0, "RO", "COMP", 0, REG_FORMAT_STRING);
    
        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]);
            RegisterMap *regmap = node->get_RegisterMap();
            scrap_span_next = regmap->getSpan("fpga/scrap_RW");
            if (scrap_span_next > scrap_span_prev) {
                scrap_span = scrap_span_next;
            }
            scrap_span_prev = scrap_span_next;
        }
        cout << "scrap_span=" << scrap_span;
        scrap_span *= nodes.size();
        cout << ", new scrap_span=" << scrap_span << endl;
        pointMap->add_register("fpga_scrap_R",   0, scrap_span, 0xffffffff, 0, "RO", "COMP", 0, REG_FORMAT_INTEGER);
        pointMap->add_register("fpga_scrap_RW",  0, scrap_span, 0xffffffff, 0, "RW", "COMP", 0, REG_FORMAT_INTEGER);
    
        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]);
            RegisterMap *regmap = node->get_RegisterMap();
            weights_span_next = regmap->getSpan("fpga/weights_RW");
            if (weights_span_next > weights_span_prev) {
                weights_span = weights_span_next;
            }
            weights_span_prev = weights_span_next;
        }
        cout << "weights_span=" << weights_span;
        weights_span *= nodes.size();
        cout << ", new weights_span=" << weights_span << endl;
        pointMap->add_register("fpga_weights_R",   0, weights_span, 0xffffffff, 0, "RO", "COMP", 0, REG_FORMAT_INT16);
        pointMap->add_register("fpga_weights_RW",  0, weights_span, 0xffffffff, 0, "RW", "COMP", 0, 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->GetEnabled());
        }
        return enabled;
    }
    
    uint Fpga::node_number(Node *node)
    {
        return (node->GetUniboardNr() * 4) + node->GetLocalNr();
    }
    
    RegisterMap * Fpga::get_pointMap(void)
    {
        return pointMap;
    }
    
    bool Fpga::point(const uint clientId, TermOutput& termout, const char cmd, const string addr, 
                     const unsigned int *data, const int nvalues)
    {
        bool ret, retval = false;
        uint retcnt = 0;
    
        termout.clear();
        string relative_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;
        }
    
        // FIXME: move these relative_addr to some new pointmap entry
        if (addr == "fpga_mask_RW") {
            relative_addr = "fpga/enable_mask_RW";
        } 
        else if (addr == "fpga_status_R") {
            relative_addr = "fpga/status";
        } 
        else if (addr == "fpga_temp_R") {
            relative_addr = "fpga/temp";
        } 
        else if (addr == "fpga_version_R") {
            relative_addr = "fpga/name";
        } 
        else if (addr == "fpga_firmware_version_R") {
            relative_addr = "fpga/firmware_version";
        } 
        else if (addr == "fpga_hardware_version_R") {
            relative_addr = "fpga/hardware_version";        
        } 
        else if (addr == "fpga_scrap_R") {
            relative_addr = "fpga/scrap_R";
        } 
        else if (addr == "fpga_scrap_RW") {
            relative_addr = "fpga/scrap_RW";
        } 
        else if (addr == "fpga_weights_R") {
            relative_addr = "fpga/weights_R";
        } 
        else if (addr == "fpga_weights_RW") {
            relative_addr = "fpga/weights_RW";
        } 
        else {
            retval = false;
            termout.strerr << "no such register: " << addr;
        }
    
        int format = pointMap->getFormat(addr);
    
        vector<int> nodes = get_all_nodes();
    
        ostringstream strs, strs_pre;
        TermOutput termresults;
    
        termout.strout << "nodes=[";
        for (auto n : nodes) {
            termout.strout << n << " ";
        }
        termout.strout << "]";
    
        if (cmd == 'R') {
            termout.strout << " point read ok";
            retval = true;
        } 
        else if (cmd == 'W') {
            if (nvalues < (int)pointMap->getSpan(addr)) {
                termout.strerr << "point write nvalues < span" << endl;
                return false;
            }
            termout.strout << " point write ok";
            retval = true;
        }
    
        strs_pre << "[";
        for (uint idx = 0; idx<nodes.size(); idx++) {
            auto node = select_node(nodes[idx]);
            uint node_nr = node_number(node);
    
            RegisterMap *regmap = node->get_RegisterMap();
            int span = regmap->getSpan(relative_addr);
            int nof_values = nvalues;
            if (nvalues < 0 || nvalues > span) {
                nof_values = span;
            }
    
            if (idx > 0) {
                strs_pre << ",";
            }
        
            strs.str(""); strs.clear();
            ret = false;
            try {
                uint didx = 0;
                if (cmd == 'W') {
                    didx = idx * nof_values;
                }
                if ((ret = node->exec_cmd(clientId, strs, cmd, relative_addr, type, instance, 
                                          &data[didx], nof_values, format))) {
                    retcnt++;
                }
            } catch (exception& e) {
                termout.strerr << e.what() << endl;
            }
            strs_pre << "(" << node_nr << "," << (ret ? "0)" : "1)");
        
        }
        strs_pre << "]";
        retval = (retcnt == nodes.size());
        if (!retval) {
            termout.strout << strs_pre.str();
            return false;
        }
    
        termout.nof_vals = pointMap->getSpan(addr);
        termout.datatype = pointMap->getFormat(addr);
        
        termout.strout << "[";
        for (uint idx=0; idx<nodes.size(); idx++) {
            auto node = select_node(nodes[idx]);
            uint node_nr = node_number(node);
            if (idx > 0) {
                termout.strout << ",";
            }
        
            strs.str("");
            strs.clear();
            ret = false;
            termresults.clear();
            try {
                if ((ret = node->exec_reply(clientId, termresults))) {
                    retcnt++;
                }
            } catch (exception& e) {
                termout.strerr << e.what() << endl;
            }
            if (cmd == 'R') {
                termout.strout << "(" << node_nr << (ret ? ",0,[" : ",1,[") << termresults.strout.str() << "])";
    
                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_INTEGER: {
                        int *ptr_in = (int *)termresults.val;
                        int *ptr_out = (int *)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_INT16: {
                        short *ptr_in = (short *)termresults.val;
                        short *ptr_out = (short *)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_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_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') {
                termout.strout << "(" << node_nr << "," << (ret ? "0)" : "1)");
            }
        }
    
        termout.strout << "]";
        if (nodes.size() == 0) {
            termout.strerr << "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;
    }