diff --git a/src/cmd.cpp b/src/cmd.cpp index 4d5fd7750176cebdf8503ad1c10e749554d31c7d..a2574a260c31a12ece5e27670f9e16f20a937f4b 100644 --- a/src/cmd.cpp +++ b/src/cmd.cpp @@ -87,10 +87,10 @@ CMDstatus CMD::command(string line, TermOutput& termout, string& cmdname, Server */ if(cmd == INFO) { req_ret = Info(argc,argv,termout,sd); - } else if(cmd == MREAD) { - req_ret = Mread(argc,argv,termout,sd); - } else if(cmd == MWRITE) { - req_ret = Mwrite(argc,argv,termout,sd); + } else if(cmd == MMREAD) { + req_ret = MMread(argc,argv,termout,sd); + } else if(cmd == MMWRITE) { + req_ret = MMwrite(argc,argv,termout,sd); } else if(cmd == RELOAD) { req_ret = Reload(argc,argv,termout,sd); /* @@ -156,7 +156,7 @@ CMDstatus CMD::Info(int argc, char* argv[], TermOutput& termout, Serverdat *sd) if (vm.count("help")) { termout.strout << "Usage: " << INFO << " [options] /unb..." << endl << "Options: " << generic << endl - << "Example: ls /unb0/pn3" << endl; + << "Example: list /unb0/pn3" << endl; return {CMD_STATUS_OK,0,0}; } if (vm.count("version")) { @@ -188,7 +188,7 @@ CMDstatus CMD::Info(int argc, char* argv[], TermOutput& termout, Serverdat *sd) return ret; } -CMDstatus CMD::Mread(int argc, char* argv[], TermOutput& termout, Serverdat *sd) +CMDstatus CMD::MMread(int argc, char* argv[], TermOutput& termout, Serverdat *sd) { CMDstatus ret = {CMD_STATUS_ERROR,0,0}; @@ -219,7 +219,7 @@ CMDstatus CMD::Mread(int argc, char* argv[], TermOutput& termout, Serverdat *sd) po::notify(vm); if (vm.count("help")) { - termout.strout << "usage: " << MREAD << " [options] file(s)" << endl + termout.strout << "usage: " << MMREAD << " [options] file(s)" << endl << "Options: " << generic << endl << "Example 1: read --nvalues=1 /unb0/pn3/mm/ppsh/ppsh/status" << endl << "Example 2: read /unb[0:10,15]/pn[0:3]/mm/ppsh/ppsh/status" << endl @@ -243,7 +243,7 @@ CMDstatus CMD::Mread(int argc, char* argv[], TermOutput& termout, Serverdat *sd) return ret; } -CMDstatus CMD::Mwrite(int argc, char* argv[], TermOutput& termout, Serverdat *sd) +CMDstatus CMD::MMwrite(int argc, char* argv[], TermOutput& termout, Serverdat *sd) { CMDstatus ret = {CMD_STATUS_ERROR,0,0}; @@ -274,7 +274,7 @@ CMDstatus CMD::Mwrite(int argc, char* argv[], TermOutput& termout, Serverdat *sd po::notify(vm); if (vm.count("help")) { - termout.strout << "usage: " << MWRITE << " [options] file(s)" << endl + termout.strout << "usage: " << MMWRITE << " [options] file(s)" << endl << "Options: " << generic << endl << "Example: write --offs=1 --data=[1,2,3,4] /unb0/pn3/mm/sens/sens/temp_high" << endl; return {CMD_STATUS_OK,0,0}; diff --git a/src/cmd.h b/src/cmd.h index 3898a8255bd25987714bd6964e7220075ff15b7b..8a247fff97871ff91ea6d4106f466ff5ca83f810 100644 --- a/src/cmd.h +++ b/src/cmd.h @@ -48,12 +48,12 @@ class CMD { private: // (1) - const std::string HELP="help"; - const std::string QUIT="quit"; - const std::string INFO="ls"; - const std::string MREAD="read"; - const std::string MWRITE="write"; - const std::string RELOAD="reload"; + const std::string HELP = "help"; + const std::string QUIT = "quit"; + const std::string INFO = "list"; + const std::string MMREAD = "read"; + const std::string MMWRITE = "write"; + const std::string RELOAD = "reload"; std::vector<std::string> supported_cmds; @@ -61,8 +61,8 @@ private: // (3) CMDstatus Info(int argc, char* argv[], TermOutput& termout, Serverdat *sd); - CMDstatus Mread(int argc, char* argv[], TermOutput& termout, Serverdat *sd); - CMDstatus Mwrite(int argc, char* argv[], TermOutput& termout, Serverdat *sd); + CMDstatus MMread(int argc, char* argv[], TermOutput& termout, Serverdat *sd); + CMDstatus MMwrite(int argc, char* argv[], TermOutput& termout, Serverdat *sd); CMDstatus Reload(int argc, char* argv[], TermOutput& termout, Serverdat *sd); public: @@ -71,8 +71,8 @@ private: supported_cmds.push_back(HELP); supported_cmds.push_back(QUIT); supported_cmds.push_back(INFO); - supported_cmds.push_back(MREAD); - supported_cmds.push_back(MWRITE); + supported_cmds.push_back(MMREAD); + supported_cmds.push_back(MMWRITE); supported_cmds.push_back(RELOAD); } diff --git a/src/io/unbos.cpp b/src/io/unbos.cpp index 897baf525d80c23c956a382b37517d5ad8ce9059..5fa57c8ddeaa4611c978cc21aeeff6b18cf67f46 100644 --- a/src/io/unbos.cpp +++ b/src/io/unbos.cpp @@ -130,7 +130,9 @@ bool UNBos::Read(const uint32_t opcode, const uint32_t addr, const uint nvalues, nreceived += _nvalues; } - if(retries) cerr << "UNBos::Read() retries=" << retries << endl; + if(retries) { + cerr << "UNBos::Read() retries=" << retries << (retstat==0 ? " (recovered)" : " (failed)") << endl; + } if(retstat==0) return true; else return false; } @@ -208,7 +210,9 @@ bool UNBos::Write(const uint32_t opcode, const uint32_t addr, const uint nvalues nsent += _nvalues; } - if(retries) cerr << "UNBos::Write() retries=" << retries << endl; + if(retries) { + cerr << "UNBos::Write() retries=" << retries << (retstat==0 ? " (recovered)" : " (failed)") << endl; + } if(retstat==0) return true; else return false; } @@ -248,15 +252,29 @@ void UNBos::print_reply_packet(const uint8_t *pkt, const int len) printf("\n"); } -bool UNBos::readRegister(uint32_t addr, uint32_t nvalues, uint32_t *data_ptr) +bool UNBos::readRegister(uint32_t addr, uint32_t nvalues, uint32_t *data_ptr, const bool isfifo) { + uint32_t opcode; if(data_ptr==NULL) throw runtime_error("UNBos::readRegister data_ptr=NULL"); - return Read(UNBOS_OPCODE_MEMORY_READ, addr, nvalues, data_ptr); + if(isfifo) { + opcode = UNBOS_OPCODE_FIFO_READ; + } else { + opcode = UNBOS_OPCODE_MEMORY_READ; + } + return Read(opcode, addr, nvalues, data_ptr); } -bool UNBos::writeRegister(uint32_t addr, uint32_t nvalues, const uint32_t *data_ptr) +bool UNBos::writeRegister(uint32_t addr, uint32_t nvalues, const uint32_t *data_ptr, const bool isfifo) { + uint32_t opcode; if(data_ptr==NULL) throw runtime_error("UNBos::writeRegister data_ptr=NULL"); - return Write(UNBOS_OPCODE_MEMORY_WRITE, addr, nvalues, data_ptr); + if(isfifo) { + opcode = UNBOS_OPCODE_FIFO_WRITE; +cout << "UNBOS fifo write" << endl; + } else { + opcode = UNBOS_OPCODE_MEMORY_WRITE; + + } + return Write(opcode, addr, nvalues, data_ptr); } diff --git a/src/io/unbos.h b/src/io/unbos.h index 107154e54a6f8e85ec2be11668773cd4c0d1e2a9..7f4d6ccc7ff1af53e0f089d770dcce95e42fd13f 100644 --- a/src/io/unbos.h +++ b/src/io/unbos.h @@ -109,7 +109,7 @@ class UNBos protected: uint32_t seq_nr; udpsocket *commdev; - +int leon; public: int count; @@ -133,8 +133,8 @@ protected: public: bool Write(const uint32_t opcode, const uint32_t addr, const uint nvalues, const uint32_t *buf); bool Read(const uint32_t opcode, const uint32_t addr, const uint nvalues, uint32_t *buf); - bool writeRegister(uint32_t addr, uint32_t nvalues, const uint32_t *data_ptr); - bool readRegister(uint32_t addr, uint32_t nvalues, uint32_t *data_ptr); + bool writeRegister(uint32_t addr, uint32_t nvalues, const uint32_t *data_ptr, const bool isfifo=false); + bool readRegister(uint32_t addr, uint32_t nvalues, uint32_t *data_ptr, const bool isfifo=false); }; #endif diff --git a/src/periph/system.cpp b/src/periph/system.cpp index 27f59715e43e2a8606c291c9950c93bebc22b537..6b4a4f748236eae01691f7bfba7f767afdf0ca8d 100644 --- a/src/periph/system.cpp +++ b/src/periph/system.cpp @@ -32,7 +32,7 @@ #include <arpa/inet.h> #include "system.h" -#include "../tools/ccfg.h" +#include "../tools/mmap.h" using namespace std; @@ -49,12 +49,12 @@ Periph_system::Periph_system(UNBos &commdev, registerMap = new RegisterMap(read_reg_map()); // Add composite registers: - registerMap->add_register("dev/system", 0, 0, 0xffffffff, 0, "RO"); - registerMap->add_register("dev/name", 0, 0, 0xffffffff, 0, "RO"); - registerMap->add_register("dev/stamps", 0, 0, 0xffffffff, 0, "RO"); - registerMap->add_register("dev/note", 0, 0, 0xffffffff, 0, "RO"); - registerMap->add_register("dev/sensors", 0, 0, 0xffffffff, 0, "RO"); - registerMap->add_register("dev/status", 0, 0, 0xffffffff, 0, "RO"); + registerMap->add_register("dev/system", 0, 0, 0xffffffff, 0, "RO", "COMP"); + registerMap->add_register("dev/name", 0, 0, 0xffffffff, 0, "RO", "COMP"); + registerMap->add_register("dev/stamps", 0, 0, 0xffffffff, 0, "RO", "COMP"); + registerMap->add_register("dev/note", 0, 0, 0xffffffff, 0, "RO", "COMP"); + registerMap->add_register("dev/sensors", 0, 0, 0xffffffff, 0, "RO", "COMP"); + registerMap->add_register("dev/status", 0, 0, 0xffffffff, 0, "RO", "COMP"); try { std::string design_name = read_design_name(); @@ -63,7 +63,8 @@ Periph_system::Periph_system(UNBos &commdev, } } -bool Periph_system::Read(const string addr_str, const uint32_t offset, const uint32_t nvalues, uint32_t *data_ptr) +bool Periph_system::Read(const string addr_str, const uint32_t offset, const uint32_t nvalues, + uint32_t *data_ptr) { bool ret; uint32_t addr = registerMap->getValidAddr(addr_str,offset,nvalues); @@ -71,8 +72,9 @@ bool Periph_system::Read(const string addr_str, const uint32_t offset, const uin uint32_t mask = registerMap->getMask(addr_str); uint32_t shift = registerMap->getShift(addr_str); + bool isfifo = registerMap->type_isfifo(addr_str); - ret = unbos.readRegister(addr,nvalues,data_ptr); + ret = unbos.readRegister(addr,nvalues,data_ptr,isfifo); if(ret && (shift != 0 || mask != 0xffffffff)) { for(uint32_t i=0; i < nvalues; i++) { data_ptr[i] &= mask; @@ -82,13 +84,15 @@ bool Periph_system::Read(const string addr_str, const uint32_t offset, const uin return ret; } -bool Periph_system::Write(const string addr_str, const uint32_t offset, const uint32_t nvalues, uint32_t *data_ptr) +bool Periph_system::Write(const string addr_str, const uint32_t offset, const uint32_t nvalues, + uint32_t *data_ptr) { uint32_t addr = registerMap->getValidAddr(addr_str,offset,nvalues); registerMap->getWritePermission(addr_str); uint32_t shift = registerMap->getShift(addr_str); uint32_t mask = registerMap->getMask(addr_str); + bool isfifo = registerMap->type_isfifo(addr_str); if(shift != 0 || mask != 0xffffffff) { for(uint32_t i=0; i<nvalues; i++) { @@ -96,7 +100,7 @@ bool Periph_system::Write(const string addr_str, const uint32_t offset, const ui data_ptr[i] &= mask; } } - return unbos.writeRegister(addr,nvalues,data_ptr); + return unbos.writeRegister(addr,nvalues,data_ptr,isfifo); } bool Periph_system::read_unb_status(ostringstream& strs) @@ -124,7 +128,7 @@ bool Periph_system::read_unb_status(ostringstream& strs) bool Periph_system::read_system_info(ostringstream& strs) { uint32_t data; - bool retval = Read("mm/system/info/info",0,1,&data); + bool retval = Read("mm/unb2b/system/info",0,1,&data); std::string design_name = read_design_name(); strs << "design_name=" << design_name << ", "; @@ -148,8 +152,8 @@ bool Periph_system::read_system_info(ostringstream& strs) design_name.c_str(), firmware_version, my_expected_design_name.c_str(), my_expected_firmware_version); - my_current_status = "offline"; - registerMap->setAllPermission_NA(); + //my_current_status = "offline"; + //registerMap->setAllPermission_NA(); } return retval; } @@ -188,7 +192,7 @@ string Periph_system::read_design_name(void) uint32_t nof_design_name_regs = 4; uint32_t nvalues = nof_design_name_regs; uint32_t *data = new uint32_t[nvalues * sizeof(uint32_t)+1]; - bool retval = Read("mm/system/info/info", 2, nvalues, data); + bool retval = Read("mm/unb2b/system/info", 2, nvalues, data); char *str_ptr = (char *)data; string name = string(str_ptr); delete[] data; @@ -200,7 +204,7 @@ string Periph_system::read_design_note(void) uint32_t nof_design_name_regs = 4; uint32_t nvalues = nof_design_name_regs; uint32_t *data = new uint32_t[nvalues * sizeof(uint32_t)+1]; - bool retval = Read("mm/system/info/info", 20, nvalues,data); + bool retval = Read("mm/unb2b/system/info", 20, nvalues,data); data[nvalues] = 0; // add end of string char char *str_ptr = (char *)data; string note = string(str_ptr); @@ -213,7 +217,7 @@ bool Periph_system::read_stamps(ostringstream& strs) uint32_t nof_regs = 3; uint32_t nvalues = nof_regs; uint32_t *data = new uint32_t[nvalues * sizeof(uint32_t)+1]; - bool retval = Read("mm/system/info/info", 15, nvalues, data); + bool retval = Read("mm/unb2b/system/info", 15, nvalues, data); strs << " Stamp: date=" << data[0] << endl; strs << " Stamp: time=" << data[1] << endl; @@ -228,7 +232,7 @@ bool Periph_system::read_unb_sensors(ostringstream& strs, const uint nodeNr) uint32_t nvalues = 1; uint32_t *data = new uint32_t[nvalues * sizeof(uint32_t)]; - retval = Read("mm/sens/sens/sens_data0", 0, nvalues, data); + retval = Read("mm/unb2b/fpga/temp", 0, nvalues, data); char str[1000]; sprintf(str," FPGA temperature = %d [degC]\n", data[0]); strs << str; @@ -242,29 +246,13 @@ bool Periph_system::read_unb_sensor(uint32_t *sensor, const uint nodeNr) uint32_t nvalues = 1; uint32_t *data = new uint32_t[nvalues * sizeof(uint32_t)]; - retval = Read("mm/sens/sens/sens_data0", 0, nvalues, data); + retval = Read("mm/unb2b/fpga/temp", 0, nvalues, data); *sensor = data[0]; delete[] data; return retval; } -bool Periph_system::read_temp_high(ostringstream& strs) -{ - bool retval = false; - uint32_t data; - retval = Read("mm/sens/sens/temp_high", 5, 1, &data); - strs << " High temp limit = " << data << " [degC]" << endl; - return retval; -} - -bool Periph_system::write_temp_high(ostringstream& strs, const int val) -{ - if(val < 10) throw runtime_error("bad high temp value"); - uint32_t data = val; - return Write("mm/sens/sens/temp_high", 5, 1, &data); -} - bool Periph_system::write_wdi_override(ostringstream& strs) { uint32_t data = 0xB007FAC7; @@ -301,9 +289,7 @@ RegisterMap Periph_system::read_reg_map(void) cout << "Periph_system::read_reg_map:\n" << reg_map_str << endl; delete[] data; - istringstream iss_regmap_step1(reg_map_str); - istringstream iss_regmap_step2(reg_map_str); - reg = ccfg_to_regmap(iss_regmap_step1); - return ccfg_upe_to_regmap_add(iss_regmap_step2, reg); + istringstream iss_regmap(reg_map_str); + return mmap_to_regmap(iss_regmap); } diff --git a/src/periph/system.h b/src/periph/system.h index 8a3a2676b232358e9fab1c05b83b36e273f8ea39..dd5a2586c06011b2011abe36e2683cb61b1c0428 100644 --- a/src/periph/system.h +++ b/src/periph/system.h @@ -34,8 +34,10 @@ private: uint my_expected_firmware_version; std::string my_current_status; - bool Read(const string addr_str, const uint32_t offset, const uint32_t nvalues, uint32_t *data_ptr); - bool Write(const string addr_str, const uint32_t offset, const uint32_t nvalues, uint32_t *data_ptr); + bool Read(const string addr_str, const uint32_t offset, const uint32_t nvalues, + uint32_t *data_ptr); + bool Write(const string addr_str, const uint32_t offset, const uint32_t nvalues, + uint32_t *data_ptr); public: Periph_system(UNBos &unbos, const string expected_design_name, const uint expected_firmware_version); @@ -52,8 +54,6 @@ public: bool read_stamps(ostringstream& strs); bool read_unb_sensor(uint32_t *sensor, const uint nodeNr); bool read_unb_sensors(ostringstream& strs, const uint nodeId); - bool read_temp_high(ostringstream& strs); - bool write_temp_high(ostringstream& strs, const int val); bool write_wdi_override(ostringstream& strs); RegisterMap read_reg_map(void); RegisterMap * getRegisterMap(void) { return registerMap; }; diff --git a/src/registers.cpp b/src/registers.cpp index 98917c9362831a8088be789e321c928b2f9ce41c..67f60047db5555a2ccac8058026be7312f23a2da 100644 --- a/src/registers.cpp +++ b/src/registers.cpp @@ -24,13 +24,48 @@ using namespace std; -void RegisterMap::add_register(const std::string name, const uint32_t base, +bool RegisterMap::add_register(const std::string name, const uint32_t base, const uint32_t span, const uint32_t mask, - const uint32_t shift, const std::string access) + const uint32_t shift, const std::string access, + const std::string type) { cout << "RegisterMap::add_register: " << name << endl; - register_info r={base, span, mask, shift, access}; + if(find_register(name)) { + cerr << "RegisterMap::add_register: " << name << " already exist!" << endl; + return false; + } + register_info r={base, span, mask, shift, access, type}; reg.insert(reg.end(), std::pair<std::string, register_info>(name, r)); + return true; +} + +bool RegisterMap::update_register(const std::string name, const uint32_t base, + const uint32_t span, const uint32_t mask, + const uint32_t shift, const std::string access, + const std::string type) +{ + cout << "RegisterMap::update_register: " << name << endl; + if(!find_register(name)) { + cerr << "RegisterMap::update_register: " << name << " not exist!" << endl; + return false; + } + reg[name].type = type; + reg[name].access = access; + reg[name].shift = shift; + reg[name].mask = mask; + reg[name].span = span; + reg[name].base = base; + return true; +} + +bool RegisterMap::find_register(std::string name) +{ + bool ret=false; + auto i = reg.find(name); + if (i != reg.end()) { + ret = true; + } + return ret; } void RegisterMap::print(ostringstream& strs, std::string prefix) @@ -41,7 +76,8 @@ void RegisterMap::print(ostringstream& strs, std::string prefix) << dec << m.second.span << " mask=0x" << hex << m.second.mask << " shift=" << dec << m.second.shift << " access=" - << m.second.access << endl; + << m.second.access << " type=" + << m.second.type << endl; } } @@ -53,10 +89,12 @@ void RegisterMap::print_screen(void) << dec << m.second.span << " mask=0x" << hex << m.second.mask << " shift=" << dec << m.second.shift << " access=" - << m.second.access << endl; + << m.second.access << " type=" + << m.second.type << endl; } } + std::vector<std::string> RegisterMap::getRegnames(std::string prefix) { std::vector<std::string> regnames; @@ -75,6 +113,7 @@ std::vector<std::string> RegisterMap::getRegnames_full(std::string prefix) ss.str(""); ss.clear(); ss << m.second.access << " " + << std::setw(4) << m.second.type << " " << "0x" << std::setfill('0') << std::hex << std::setw(8) << m.second.base << " " << std::setfill(' ') << std::dec << std::setw(4) << m.second.span << " " << prefix << m.first; @@ -85,14 +124,19 @@ std::vector<std::string> RegisterMap::getRegnames_full(std::string prefix) } -uint32_t RegisterMap::getValidAddr(const std::string name, const uint32_t offset, const uint32_t size) +uint32_t RegisterMap::getValidAddr(const std::string name, const uint32_t offset, + const uint32_t size) { + if(!find_register(name)) { + throw runtime_error("Register["+name+"] not existing!"); + } uint32_t _offset = offset * sizeof(uint32_t); uint32_t end = (size + offset);// * sizeof(uint32_t); uint32_t base = getBaseAddr(name); uint32_t span = getSpan(name); - if(end > span) { + + if(end > span && !type_isfifo(name)) { throw runtime_error("Register["+name+"] getValidAddr() out of range!"); } uint32_t addr = base + _offset; diff --git a/src/registers.h b/src/registers.h index 739d62b943cb9153d0dca5c89360d6e5490a50bb..b717f2826ed3f01ab2b58c679a79b013333bd46c 100644 --- a/src/registers.h +++ b/src/registers.h @@ -36,6 +36,7 @@ class RegisterMap { uint32_t mask; uint32_t shift; std::string access; + std::string type; } register_info; std::map <std::string, register_info> reg; @@ -45,8 +46,13 @@ class RegisterMap { }; ~RegisterMap() {}; - void add_register(const std::string name, const uint32_t base, const uint32_t span, - const uint32_t mask, const uint32_t shift, const std::string access); + bool add_register(const std::string name, const uint32_t base, const uint32_t span, + const uint32_t mask, const uint32_t shift, const std::string access, + const std::string type); + bool update_register(const std::string name, const uint32_t base, const uint32_t span, + const uint32_t mask, const uint32_t shift, const std::string access, + const std::string type); + bool find_register(std::string name); void print(std::ostringstream& strs, std::string prefix); void print_screen(void); uint32_t getBaseAddr(const std::string name) { return reg[name].base; } @@ -54,7 +60,10 @@ class RegisterMap { std::string getPerm(const std::string name) { return reg[name].access; } uint32_t getMask(const std::string name) { return reg[name].mask; } uint32_t getShift(const std::string name) { return reg[name].shift; } - uint32_t getValidAddr(const std::string name, const uint32_t offset, const uint32_t size); + std::string getType(const std::string name) { return reg[name].type; } + bool type_isfifo(const std::string name) { return (reg[name].type == "FIFO"); } + uint32_t getValidAddr(const std::string name, const uint32_t offset, + const uint32_t size); bool getReadPermission(const std::string name); bool getWritePermission(const std::string name); void setPermission_NA(const std::string name) { reg[name].access = "NA"; } diff --git a/src/sdpunb.cpp b/src/sdpunb.cpp index 527d771fcc789826109aac63207f538e55e8e4c1..6d9e94e556c0ffd0e1aa8bf13ea5c85b32ceb692 100644 --- a/src/sdpunb.cpp +++ b/src/sdpunb.cpp @@ -73,32 +73,25 @@ void monitor(void) CMDstatus cmdstatus = {CMD_STATUS_OK, 0,0}; CMDstatus cmdstatusnew = cmdstatus; TermOutput termout; -#define c_NOF_RETRIES_MONITOR 3 - int retries = c_NOF_RETRIES_MONITOR; -// while(ServerRunning) { -// usleep(1000000); -// } + while(ServerRunning) { + usleep(1000000); + } while(ServerRunning) { usleep(1000000); while(!SD.monitor_mutex.try_lock()) { cerr << "mutex not ready\n"; usleep(100000); } - if(!SD.unb->monitor(termout)) { - retries--; - cerr << "Retrying " << retries << endl; - } else { - retries = c_NOF_RETRIES_MONITOR; - } + SD.unb->monitor(termout); SD.monitor_mutex.unlock(); if(cmdstatusnew.status != CMD_EMPTY) cmdstatus = cmdstatusnew; cout << "Monitor thread: " << print_termout(termout) << endl; termout.clear(); - if(retries <= 0) { + //if(retries <= 0) { //cerr << "Re-initializing, Read register maps again!" << endl; //raise(SIGHUP) - } + //} } } diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am index c674ddbb17693d76b760732d06e2d34d448ed516..192b92bef6a455483040e49e53f0e62b2f58c53c 100644 --- a/src/tools/Makefile.am +++ b/src/tools/Makefile.am @@ -11,7 +11,7 @@ AM_CXXFLAGS = -std=c++11 -pedantic -Wall -Woverloaded-virtual -Wwrite-strings -D # ############################################################################ -tools_SOURCES = parse.cpp parse.h util.cpp util.h ccfg.cpp ccfg.h +tools_SOURCES = parse.cpp parse.h util.cpp util.h mmap.cpp mmap.h # the sources to add to the library and to add to the source distribution libtools_a_SOURCES = $(tools_SOURCES) diff --git a/src/tools/ccfg.cpp b/src/tools/ccfg.cpp deleted file mode 100644 index 315b179d473aaed8bd756815630bbb5ca265ce17..0000000000000000000000000000000000000000 --- a/src/tools/ccfg.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright 2020 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten, - * ASTRON Netherlands Institute for Radio Astronomy - * Licensed under the Apache License, Version 2.0 (the "License"); - * - * you may not use this file except in compliance with the License. - * - * 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. - * - * See ../../LICENSE.txt for more info. - */ - -#include <iostream> -#include <sstream> -#include <iomanip> -#include <istream> -#include <fstream> -#include <string> -#include <strings.h> -#include <boost/numeric/ublas/io.hpp> -#include <boost/array.hpp> -#include <boost/regex.hpp> - -#include "ccfg.h" - -using namespace std; -using namespace boost::numeric::ublas; - - -RegisterMap ccfg_to_regmap(std::istringstream& iss) -{ - RegisterMap regmap; - ostringstream err_str; - - -// DistrRAM 0x00000000 len=32 RO system info info -#define RE_CCFG_LINE_DistrRAM "^\\s*DistrRAM\\s+0x\\S+\\s+len=\\d+\\s+[R,W][O,W]\\s+\\S+\\s+\\S+\\s+.*$" -//#define RE_CCFG_LINE_DistrRAM "^\\s*DistrRAM\\s+.*$" - -// BitField 0x000000E0 b[31:0] WO ctrl pio_wdi nios_reset -#define RE_CCFG_LINE_BitField "^\\s*BitField\\s+0x\\S+\\s+b\\[\\d+:\\d+\\]\\s+[R,W][O,W]\\s+\\S+\\s+\\S+\\s+.*$" -//#define RE_CCFG_LINE_BitField "^\\s*BitField\\s+.*$" - -// BlockRAM 0x00001000 len=1024 RW eth1g eth data -#define RE_CCFG_LINE_BlockRAM "^\\s*BlockRAM\\s+0x\\S+\\s+len=\\d+\\s+[R,W][O,W]\\s+\\S+\\s+\\S+\\s+.*$" -//#define RE_CCFG_LINE_BlockRAM "^\\s*BlockRAM\\s+.*$" - - - boost::regex comment_re, spaces_re, DistrRAM_re, BitField_re, BlockRAM_re; - - boost::cmatch matches; - comment_re = string("^\\s*#+.*$"); - spaces_re = string("^\\s*$"); - DistrRAM_re = string(RE_CCFG_LINE_DistrRAM); - BitField_re = string(RE_CCFG_LINE_BitField); - BlockRAM_re = string(RE_CCFG_LINE_BlockRAM); - - char line[250]; - while(iss.getline(line, sizeof(line))) { - - if (regex_match(line, comment_re)) { - //cout << "import_ccfg_file match: comment ok" << endl; - } else if (regex_match(line, spaces_re)) { - //cout << "import_ccfg_file match: spaces ok" << endl; - } else if (regex_match(line, DistrRAM_re)) { - //cout << "import_ccfg_file match: DistrRAM ok" << endl; - stringstream ss(line); - string prefx, perm, peripheral, regname, regfield; - uint base, span; - char c; - - // DistrRAM 0x00000000 len=32 RO system info info - ss >> prefx; - ss >> hex >> base; // in dword addresses - //base *= 4; // to byte addresses - ss >> c; // 'l' - ss >> c; // 'e' - ss >> c; // 'n' - ss >> c; // '=' - ss >> dec >> span; // in dwords - //span *= 4; // to bytes - ss >> perm; - ss >> peripheral; - ss >> regname; - ss >> regfield; - if (ss.fail() || ss.bad()) { - cerr << "import_ccfg_file: invalid DistrRAM" << endl; - } else { - regmap.add_register("mm/"+peripheral+"/"+regname+"/"+regfield,base,span,0xffffffff,0,perm); - } - - } else if (regex_match(line, BitField_re)) { - //cout << "import_ccfg_file match: BitField ok" << endl; - stringstream ss(line); - string prefx, perm, peripheral, regname, regfield; - uint base, span; - uint32_t mask,shift; - char c; - uint mask_to, mask_from; - - // BitField 0x000000E0 b[31:0] WO ctrl pio_wdi nios_reset - ss >> prefx; - ss >> hex >> base; // in dword addresses - //base *= 4; // to byte addresses - ss >> c; // 'b' - ss >> c; // '[' - ss >> dec >> mask_to; - ss >> c; // ':' - ss >> dec >> mask_from; - ss >> c; // ']' - - mask = 0; - for(uint i=mask_from;i<=mask_to;i++) { - mask |= (1<<i); - } - shift = mask_from; - //cout << "mask_to=" << dec << mask_to << " mask_from=" << mask_from << endl; - //cout << " mask=0x" << hex << mask << endl; - - span = 1; // in dwords - //span *= 4; // to bytes - ss >> perm; - ss >> peripheral; - ss >> regname; - ss >> regfield; - if (ss.fail() || ss.bad()) { - cerr << "import_ccfg_file: invalid BitField" << endl; - } else { - regmap.add_register("mm/"+peripheral+"/"+regname+"/"+regfield,base,span,mask,shift,perm); - } - - } else if (regex_match(line, BlockRAM_re)) { - //cout << "import_ccfg_file match: BlockRAM ok" << endl; - stringstream ss(line); - string prefx, perm, peripheral, regname, regfield; - uint base, span; - char c; - - // BlockRAM 0x00001000 len=1024 RW eth1g eth data - ss >> prefx; - ss >> hex >> base; // in dword addresses - //base *= 4; // to byte addresses - ss >> c; // 'l' - ss >> c; // 'e' - ss >> c; // 'n' - ss >> c; // '=' - ss >> dec >> span; // in dwords - //span *= 4; // to bytes - ss >> perm; - ss >> peripheral; - ss >> regname; - ss >> regfield; - if (ss.fail() || ss.bad()) { - cerr << "import_ccfg_file: invalid BlockRAM" << endl; - } else { - regmap.add_register("mm/"+peripheral+"/"+regname+"/"+regfield,base,span,0xffffffff,0,perm); - } - - } else { - cerr << "import_ccfg_file: error! illegal line: [" << line << "]" << endl; - } - } - - cout << "regmap:" << endl; - regmap.print_screen(); - - return regmap; -} - -RegisterMap ccfg_upe_to_regmap_add(std::istringstream& iss, RegisterMap ®map) -{ - ostringstream err_str; - -// # peripheral=system start=0x0000 span=0x0080 count=01 idx=0 stop=0x0080 -#define RE_CCFG_UPE_LINE_peripheral "^#\\s*peripheral=\\w+\\s+start=0x\\S+\\s+span=0x\\S+\\s+\\S+\\s+\\S+\\s+\\S+$" - -// # REG-SLAVE=pio_system_info no.slaves=1 len=1 (base=0x80) -#define RE_CCFG_UPE_LINE_REG_SLAVE "^#\\s*REG-SLAVE=\\w+\\s+no.slaves=\\S+\\s+len=\\S+\\s+\\S+$" - -// # RAM-SLAVE=avs_eth_0_ram -#define RE_CCFG_UPE_LINE_RAM_SLAVE "^#\\s*RAM-SLAVE=\\w+\\s+$" - -// # FIFO-SLAVE=not_seen_any_yet -#define RE_CCFG_UPE_LINE_FIFO_SLAVE "^#\\s*FIFO-SLAVE=\\w+\\s+$" - - boost::regex spaces_re, peripheral_re, REG_SLAVE_re, RAM_SLAVE_re, FIFO_SLAVE_re; - - boost::cmatch matches; - spaces_re = string("^\\s*$"); - peripheral_re = string(RE_CCFG_UPE_LINE_peripheral); - REG_SLAVE_re = string(RE_CCFG_UPE_LINE_REG_SLAVE); - RAM_SLAVE_re = string(RE_CCFG_UPE_LINE_RAM_SLAVE); - FIFO_SLAVE_re = string(RE_CCFG_UPE_LINE_FIFO_SLAVE); - - uint peripheral_addr, peripheral_span, stage = 0; - - char line[250]; - while(iss.getline(line, sizeof(line))) { - - if (regex_match(line, spaces_re)) { - cout << "ccfg_upe_to_regmap_add match: spaces ok" << endl; - - } else if (regex_match(line, peripheral_re)) { - cout << "ccfg_upe_to_regmap_add match: RE_CCFG_UPE_LINE_peripheral ok" << endl; - stringstream ss(line); - string prefx; - char c; - - // # peripheral=system start=0x0000 span=0x0080 count=01 idx=0 stop=0x0080 - ss >> c; // # - ss >> prefx; - ss >> c; // s - ss >> c; // t - ss >> c; // a - ss >> c; // r - ss >> c; // t - ss >> c; // = - - ss >> hex >> peripheral_addr; // in dword addresses - - ss >> c; // 's' - ss >> c; // 'p' - ss >> c; // 'a' - ss >> c; // 'n' - ss >> c; // '=' - ss >> hex >> peripheral_span; - peripheral_span /= 4; // byte to dwords addressing - - stage = 1; - - if (ss.fail() || ss.bad()) { - cerr << "ccfg_upe_to_regmap_add: invalid peripheral base/span" << endl; - } else { - //regmap.add_register("mm/"+peripheral+"/"+regname+"/"+regfield,base,span,0xffffffff,0,perm); - cout << "ccfg_upe_to_regmap_add: base=0x" - << hex << peripheral_addr << " span=0x" << hex << peripheral_span << endl; - } - - } else if (regex_match(line, REG_SLAVE_re)) { - cout << "ccfg_upe_to_regmap_add match: RE_CCFG_UPE_LINE_REG_SLAVE ok" << endl; - stringstream ss(line); - string peripheral; - char c; - - // # REG-SLAVE=pio_system_info no.slaves=1 len=1 (base=0x80) - ss >> c; // # - ss >> c; // R - ss >> c; // E - ss >> c; // G - ss >> c; // - - ss >> c; // S - ss >> c; // L - ss >> c; // A - ss >> c; // V - ss >> c; // E - ss >> c; // = - - ss >> peripheral; - - if (ss.fail() || ss.bad()) { - cerr << "ccfg_upe_to_regmap_add: invalid peripheral name" << endl; - } else { - transform(peripheral.begin(), peripheral.end(), peripheral.begin(), ::toupper); - cout << "ccfg_upe_to_regmap_add: peripheral=" << peripheral << endl; - if(stage == 1) { - regmap.add_register("mm/"+peripheral,peripheral_addr,peripheral_span, - 0xffffffff,0,"RW"); - } - } - stage = 0; - - } else if (regex_match(line, RAM_SLAVE_re)) { - cout << "ccfg_upe_to_regmap_add match: RE_CCFG_UPE_LINE_RAM_SLAVE ok" << endl; - stringstream ss(line); - string peripheral; - char c; - - // # RAM-SLAVE=avs_eth_0_ram - ss >> c; // # - ss >> c; // R - ss >> c; // A - ss >> c; // M - ss >> c; // - - ss >> c; // S - ss >> c; // L - ss >> c; // A - ss >> c; // V - ss >> c; // E - ss >> c; // = - - ss >> peripheral; - - if (ss.fail() || ss.bad()) { - cerr << "ccfg_upe_to_regmap_add: invalid peripheral name" << endl; - } else { - transform(peripheral.begin(), peripheral.end(), peripheral.begin(), ::toupper); - cout << "ccfg_upe_to_regmap_add: peripheral=" << peripheral << endl; - if(stage == 1) { - regmap.add_register("mm/"+peripheral,peripheral_addr,peripheral_span, - 0xffffffff,0,"RW"); - } - } - stage = 0; - - } else if (regex_match(line, FIFO_SLAVE_re)) { - cout << "ccfg_upe_to_regmap_add match: RE_CCFG_UPE_LINE_FIFO_SLAVE ok" << endl; - stringstream ss(line); - string peripheral; - char c; - - // # FIFO-SLAVE=not_seen_any_yet - ss >> c; // # - ss >> c; // F - ss >> c; // I - ss >> c; // F - ss >> c; // O - ss >> c; // - - ss >> c; // S - ss >> c; // L - ss >> c; // A - ss >> c; // V - ss >> c; // E - ss >> c; // = - - ss >> peripheral; - - if (ss.fail() || ss.bad()) { - cerr << "ccfg_upe_to_regmap_add: invalid peripheral name" << endl; - } else { - transform(peripheral.begin(), peripheral.end(), peripheral.begin(), ::toupper); - cout << "ccfg_upe_to_regmap_add: peripheral=" << peripheral << endl; - if(stage == 1) { - regmap.add_register("mm/"+peripheral,peripheral_addr,peripheral_span, - 0xffffffff,0,"RW"); - } - } - stage = 0; - - } else { - cerr << "ccfg_upe_to_regmap_add: error! illegal line: [" << line << "]" << endl; - } - } - - cout << "regmap:" << endl; - regmap.print_screen(); - - return regmap; -} - - -/* - * Some help on REGEX's - * - * - -Symbol Meaning -c Match the literal character c once, unless it is one of the special characters. -^ Match the beginning of a line. -. Match any character that isn't a newline. -$ Match the end of a line. -| Logical OR between expressions. -() Group subexpressions. -[] Define a character class. -* Match the preceding expression zero or more times. -+ Match the preceding expression one ore more times. -? Match the preceding expression zero or one time. -{n} Match the preceding expression n times. -{n,} Match the preceding expression at least n times. -{n, m} Match the preceding expression at least n times and at most m times. -\d Match a digit. -\D Match a character that is not a digit. -\w Match an alpha character, including the underscore. -\W Match a character that is not an alpha character. -\s Match a whitespace character (any of \t, \n, \r, or \f). -\S Match a non-whitespace character. -\t Tab. -\n Newline. -\r Carriage return. -\f Form feed. -\m Escape m, where m is one of the metacharacters described above: ^, ., $, |, (), [], *, +, ?, \, or /. -*/ - diff --git a/src/tools/mmap.cpp b/src/tools/mmap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f58452465332468f91e4ff6e0ea385f3ae4f5c80 --- /dev/null +++ b/src/tools/mmap.cpp @@ -0,0 +1,228 @@ +/* + * Copyright 2020 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten, + * ASTRON Netherlands Institute for Radio Astronomy + * Licensed under the Apache License, Version 2.0 (the "License"); + * + * you may not use this file except in compliance with the License. + * + * 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. + * + * See ../../LICENSE.txt for more info. + */ + +#include <iostream> +#include <sstream> +#include <iomanip> +#include <istream> +#include <fstream> +#include <string> +#include <strings.h> +#include <boost/numeric/ublas/io.hpp> +#include <boost/array.hpp> +#include <boost/regex.hpp> + +#include "mmap.h" + +using namespace std; +using namespace boost::numeric::ublas; + + +void mmap_add_register(RegisterMap& regmap, + std::string qsysname, std::string fullname, + uint base, uint span, uint32_t mask, uint32_t shift, + std::string perm, std::string type) +{ + // add full name register + regmap.add_register(fullname, base, span, mask, shift, perm, type); + // add qsys name register + if(!regmap.find_register(qsysname)) { + regmap.add_register(qsysname, base, span, mask, shift, perm, type); + } else { + uint update_base, update_span; + update_base = regmap.getBaseAddr(qsysname); + update_span = regmap.getSpan(qsysname); + update_span += span; + + if(update_base < base) { + // already have a base which is lower + regmap.update_register(qsysname, update_base, update_span, 0xffffffff, 0, "RW", type); + } else { + // this will be the new base which is lower + regmap.update_register(qsysname, base, update_span, 0xffffffff, 0, "RW", type); + } + } +} + +RegisterMap mmap_to_regmap(std::istringstream& iss) +{ + RegisterMap regmap; + ostringstream err_str; + +// unb2b rom_system info REG 0x00000000000 8192 RO b[31:0] PIO_SYSTEM_INFO +#define RE_MMAP_LINE_REG "^\\s*\\w+\\s+\\w+\\s+\\w+\\s+REG\\s+0x\\S+\\s+\\d+\\s+[R,W][O,W]\\s+b\\[\\d+:\\d+\\]\\s+\\w+\\s+.*$" +// eth1g eth data RAM 0x00000000800 1024 RW - AVS_ETH_0_RAM +#define RE_MMAP_LINE_RAM "^\\s*\\w+\\s+\\w+\\s+\\w+\\s+RAM\\s+0x\\S+\\s+\\d+\\s+[R,W][O,W]\\s+-\\s+\\w+\\s+.*$" +// epcs dpmm_data data FIFO 0x000000000e8 1 RO - REG_DPMM_DATA +#define RE_MMAP_LINE_FIFO "^\\s*\\w+\\s+\\w+\\s+\\w+\\s+FIFO\\s+0x\\S+\\s+\\d+\\s+[R,W][O,W]\\s+-\\s+\\w+\\s+.*$" + + + boost::regex comment_re, spaces_re, REG_re, RAM_re, FIFO_re; + + boost::cmatch matches; + comment_re = string("^\\s*#+.*$"); + spaces_re = string("^\\s*$"); + REG_re = string(RE_MMAP_LINE_REG); + RAM_re = string(RE_MMAP_LINE_RAM); + FIFO_re = string(RE_MMAP_LINE_FIFO); + + char line[250]; + while(iss.getline(line, sizeof(line))) { + + if (regex_match(line, comment_re)) { + //cout << "import_mmap_file match: comment ok" << endl; + } else if (regex_match(line, spaces_re)) { + //cout << "import_mmap_file match: spaces ok" << endl; + } else if (regex_match(line, REG_re)) { + cout << "import_mmap_file match: REG ok" << endl; + stringstream ss(line); + string type, perm, peripheral, regname, regfield, qsysname; + unsigned long long base44; + uint base, span; + uint32_t mask,shift; + uint mask_to, mask_from; + char c; + + ss >> peripheral; + ss >> regname; + ss >> regfield; + ss >> type; + ss >> hex >> base44; // in dword addresses + base = (uint)base44; + ss >> dec >> span; // in dwords + ss >> perm; + ss >> c; // 'b' + ss >> c; // '[' + ss >> dec >> mask_to; + ss >> c; // ':' + ss >> dec >> mask_from; + ss >> c; // ']' + + mask = 0; + for(uint i=mask_from;i<=mask_to;i++) { + mask |= (1<<i); + } + shift = mask_from; + ss >> qsysname; + + if (ss.fail() || ss.bad()) { + cerr << "import_mmap_file: invalid REG" << endl; + } else { + mmap_add_register(regmap,"mm/"+qsysname,"mm/"+peripheral+"/"+regname+"/"+regfield, + base,span,mask,shift,perm,type); + } + } else if (regex_match(line, RAM_re)) { + cout << "import_mmap_file match: RAM ok" << endl; + stringstream ss(line); + string type, perm, peripheral, regname, regfield, qsysname; + unsigned long long base44; + uint base, span; + uint32_t mask,shift; + char c; + + ss >> peripheral; + ss >> regname; + ss >> regfield; + ss >> type; + ss >> hex >> base44; // in dword addresses + base = (uint)base44; + ss >> dec >> span; // in dwords + ss >> perm; + ss >> c; // '-' + + mask = 0xffffffff; + shift = 0; + ss >> qsysname; + + if (ss.fail() || ss.bad()) { + cerr << "import_mmap_file: invalid RAM" << endl; + } else { + mmap_add_register(regmap,"mm/"+qsysname,"mm/"+peripheral+"/"+regname+"/"+regfield, + base,span,mask,shift,perm,type); + } + } else if (regex_match(line, FIFO_re)) { + cout << "import_mmap_file match: FIFO ok" << endl; + stringstream ss(line); + string type, perm, peripheral, regname, regfield, qsysname; + unsigned long long base44; + uint base, span; + uint32_t mask,shift; + char c; + + ss >> peripheral; + ss >> regname; + ss >> regfield; + ss >> type; + ss >> hex >> base44; // in dword addresses + base = (uint)base44; + ss >> dec >> span; // in dwords + ss >> perm; + ss >> c; // '-' + + mask = 0xffffffff; + shift = 0; + ss >> qsysname; + + if (ss.fail() || ss.bad()) { + cerr << "import_mmap_file: invalid FIFO" << endl; + } else { + mmap_add_register(regmap,"mm/"+qsysname,"mm/"+peripheral+"/"+regname+"/"+regfield, + base,span,mask,shift,perm,type); + } + } else { + cerr << "import_mmap_file: error! illegal line: [" << line << "]" << endl; + } + } + + cout << "regmap:" << endl; + regmap.print_screen(); + + return regmap; +} + + +/* + * Some help on REGEX's + * + * + +Symbol Meaning +c Match the literal character c once, unless it is one of the special characters. +^ Match the beginning of a line. +. Match any character that isn't a newline. +$ Match the end of a line. +| Logical OR between expressions. +() Group subexpressions. +[] Define a character class. +* Match the preceding expression zero or more times. ++ Match the preceding expression one ore more times. +? Match the preceding expression zero or one time. +{n} Match the preceding expression n times. +{n,} Match the preceding expression at least n times. +{n, m} Match the preceding expression at least n times and at most m times. +\d Match a digit. +\D Match a character that is not a digit. +\w Match an alpha character, including the underscore. +\W Match a character that is not an alpha character. +\s Match a whitespace character (any of \t, \n, \r, or \f). +\S Match a non-whitespace character. +\t Tab. +\n Newline. +\r Carriage return. +\f Form feed. +\m Escape m, where m is one of the metacharacters described above: ^, ., $, |, (), [], *, +, ?, \, or /. +*/ + diff --git a/src/tools/ccfg.h b/src/tools/mmap.h similarity index 85% rename from src/tools/ccfg.h rename to src/tools/mmap.h index a55fb2246aaa221b12405362e5175df40b996f20..b021e710cd8544f99eba15c664265c368a70f0eb 100644 --- a/src/tools/ccfg.h +++ b/src/tools/mmap.h @@ -14,8 +14,8 @@ * See ../../LICENSE.txt for more info. */ -#ifndef CCFG_H -#define CCFG_H +#ifndef MMAP_H +#define MMAP_H #include <stdlib.h> #include <sys/time.h> @@ -33,7 +33,6 @@ namespace ublas = boost::numeric::ublas; -RegisterMap ccfg_to_regmap(std::istringstream& iss); -RegisterMap ccfg_upe_to_regmap_add(std::istringstream& iss, RegisterMap& reg); +RegisterMap mmap_to_regmap(std::istringstream& iss); #endif diff --git a/src/uniboard.conf b/src/uniboard.conf index 63550ed7a9194b8d5a6f7da9bb28f7d16efc88d4..29911d96818d38da43fe853b76fbbe549a050daf 100644 --- a/src/uniboard.conf +++ b/src/uniboard.conf @@ -3,9 +3,9 @@ # NODE config: # gn ipaddr expected firmware expected version -node 0 10.99.1.1 unb2b_minimal 2 -node 1 10.99.1.2 unb2b_minimal 2 -#node 2 10.99.1.3 unb2b_minimal 2 +#node 0 10.99.1.1 unb2b_minimal 2 +#node 1 10.99.1.2 unb2b_minimal 2 +node 2 10.99.1.3 unb2b_minimal 2 #node 3 10.99.1.4 unb2b_minimal 2