// $Id: RtclRlinkConnect.cpp 1048 2018-09-22 07:41:46Z mueller $ // // Copyright 2011-2018 by Walter F.J. Mueller // // This program is free software; you may redistribute and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for complete details. // // Revision History: // Date Rev Version Comment // 2018-09-16 1047 1.6.1 coverity fixup (uninitialized scalar) // 2017-04-29 888 1.6 drop M_rawio; add M_rawread,M_rawrblk,M_rawwblk // 2017-04-22 883 1.5.2 M_amap: -testname opt addr check; add hasrbmon get // 2017-04-02 865 1.5.1 M_dump: use GetArgsDump and Dump detail // 2017-02-20 854 1.5 use Rtime // 2016-04-02 758 1.4.6 add USR_ACCESS register support (UsrAcc->usracc) // 2016-03-20 748 1.4.5 M_get/set: add timeout // 2015-05-09 676 1.4.3 M_errcnt: add -increment; M_log: add -bare,-info.. // 2015-04-19 668 1.4.2 M_wtlam: allow tout=0 for pending attn cleanup // 2015-04-12 666 1.4.1 add M_init // 2015-04-03 661 1.4 expect logic: drop estatdef, use LastExpect.. // 2015-03-28 660 1.3.3 add stat* getter/setter; M_exec: add -estaterr ect // 2015-01-06 631 1.3.2 add M_get, M_set, remove M_config // 2014-12-20 616 1.3.1 M_exec: add -edone for BlockDone checking // 2014-12-06 609 1.3 new rlink v4 iface // 2014-08-22 584 1.2.1 use nullptr // 2014-08-15 583 1.2 rb_mreq addr now 16 bit // 2014-08-02 576 1.1.7 BUGFIX: redo estatdef logic; avoid LastExpect() // 2013-02-23 492 1.1.6 use RlogFile.Name(); use Context().ErrorCount() // 2013-02-22 491 1.1.5 use new RlogFile/RlogMsg interfaces // 2013-02-02 480 1.1.4 allow empty exec commands // 2013-01-27 478 1.1.3 use RtclRlinkPort::DoRawio on M_rawio // 2013-01-06 473 1.1.2 add M_rawio: rawio -write|-read // 2011-11-28 434 1.1.1 ConfigBase(): use uint32_t for lp64 compatibility // 2011-04-23 380 1.1 use boost/bind instead of RmethDsc // 2011-04-17 376 1.0.1 M_wtlam: now correct log levels // 2011-03-27 374 1.0 Initial version // 2011-02-11 360 0.1 First draft // --------------------------------------------------------------------------- /*! \file \brief Implemenation of class RtclRlinkConnect. */ #include #include #include "boost/bind.hpp" #include "boost/thread/locks.hpp" #include "librtcltools/Rtcl.hpp" #include "librtcltools/RtclOPtr.hpp" #include "librtcltools/RtclNameSet.hpp" #include "librtcltools/RtclStats.hpp" #include "librtools/RosPrintf.hpp" #include "librtools/RlogMsg.hpp" #include "librlink/RlinkCommandList.hpp" #include "RtclRlinkPort.hpp" #include "RtclRlinkConnect.hpp" using namespace std; /*! \class Retro::RtclRlinkConnect \brief FIXME_docs */ // all method definitions in namespace Retro namespace Retro { //------------------------------------------+----------------------------------- //! Default constructor RtclRlinkConnect::RtclRlinkConnect(Tcl_Interp* interp, const char* name) : RtclProxyOwned("RlinkConnect", interp, name, new RlinkConnect()), fGets(), fSets() { AddMeth("open", boost::bind(&RtclRlinkConnect::M_open, this, _1)); AddMeth("close", boost::bind(&RtclRlinkConnect::M_close, this, _1)); AddMeth("init", boost::bind(&RtclRlinkConnect::M_init, this, _1)); AddMeth("exec", boost::bind(&RtclRlinkConnect::M_exec, this, _1)); AddMeth("amap", boost::bind(&RtclRlinkConnect::M_amap, this, _1)); AddMeth("errcnt", boost::bind(&RtclRlinkConnect::M_errcnt, this, _1)); AddMeth("wtlam", boost::bind(&RtclRlinkConnect::M_wtlam, this, _1)); AddMeth("oob", boost::bind(&RtclRlinkConnect::M_oob, this, _1)); AddMeth("rawread", boost::bind(&RtclRlinkConnect::M_rawread, this, _1)); AddMeth("rawrblk", boost::bind(&RtclRlinkConnect::M_rawrblk, this, _1)); AddMeth("rawwblk", boost::bind(&RtclRlinkConnect::M_rawwblk, this, _1)); AddMeth("stats", boost::bind(&RtclRlinkConnect::M_stats, this, _1)); AddMeth("log", boost::bind(&RtclRlinkConnect::M_log, this, _1)); AddMeth("print", boost::bind(&RtclRlinkConnect::M_print, this, _1)); AddMeth("dump", boost::bind(&RtclRlinkConnect::M_dump, this, _1)); AddMeth("get", boost::bind(&RtclRlinkConnect::M_get, this, _1)); AddMeth("set", boost::bind(&RtclRlinkConnect::M_set, this, _1)); AddMeth("$default", boost::bind(&RtclRlinkConnect::M_default, this, _1)); for (size_t i=0; i<8; i++) { fCmdnameObj[i] = Tcl_NewStringObj(RlinkCommand::CommandName(i), -1); } // attributes of RlinkConnect RlinkConnect* pobj = &Obj(); fGets.Add ("baseaddr", boost::bind(&RlinkConnect::LogBaseAddr, pobj)); fGets.Add ("basedata", boost::bind(&RlinkConnect::LogBaseData, pobj)); fGets.Add ("basestat", boost::bind(&RlinkConnect::LogBaseStat, pobj)); fGets.Add ("printlevel", boost::bind(&RlinkConnect::PrintLevel, pobj)); fGets.Add ("dumplevel", boost::bind(&RlinkConnect::DumpLevel, pobj)); fGets.Add ("tracelevel", boost::bind(&RlinkConnect::TraceLevel, pobj)); fGets.Add ("timeout", boost::bind(&RlinkConnect::Timeout, pobj)); fGets.Add ("logfile", boost::bind(&RlinkConnect::LogFileName, pobj)); fGets.Add ("initdone", boost::bind(&RlinkConnect::LinkInitDone, pobj)); fGets.Add ("sysid", boost::bind(&RlinkConnect::SysId, pobj)); fGets.Add ("usracc", boost::bind(&RlinkConnect::UsrAcc, pobj)); fGets.Add ("rbufsize", boost::bind(&RlinkConnect::RbufSize, pobj)); fGets.Add ("bsizemax", boost::bind(&RlinkConnect::BlockSizeMax, pobj)); fGets.Add ("bsizeprudent", boost::bind(&RlinkConnect::BlockSizePrudent, pobj)); fGets.Add ("hasrbmon", boost::bind(&RlinkConnect::HasRbmon, pobj)); fSets.Add ("baseaddr", boost::bind(&RlinkConnect::SetLogBaseAddr, pobj, _1)); fSets.Add ("basedata", boost::bind(&RlinkConnect::SetLogBaseData, pobj, _1)); fSets.Add ("basestat", boost::bind(&RlinkConnect::SetLogBaseStat, pobj, _1)); fSets.Add ("printlevel", boost::bind(&RlinkConnect::SetPrintLevel, pobj, _1)); fSets.Add ("dumplevel", boost::bind(&RlinkConnect::SetDumpLevel, pobj, _1)); fSets.Add ("tracelevel", boost::bind(&RlinkConnect::SetTraceLevel, pobj, _1)); fSets.Add ("timeout", boost::bind(&RlinkConnect::SetTimeout, pobj, _1)); fSets.Add ("logfile", boost::bind(&RlinkConnect::SetLogFileName, pobj, _1)); // attributes of buildin RlinkContext RlinkContext* pcntx = &Obj().Context(); fGets.Add ("statchecked", boost::bind(&RlinkContext::StatusIsChecked, pcntx)); fGets.Add ("statvalue", boost::bind(&RlinkContext::StatusValue, pcntx)); fGets.Add ("statmask", boost::bind(&RlinkContext::StatusMask, pcntx)); fSets.Add ("statvalue", boost::bind(&RlinkContext::SetStatusValue, pcntx, _1)); fSets.Add ("statmask", boost::bind(&RlinkContext::SetStatusMask, pcntx, _1)); } //------------------------------------------+----------------------------------- //! Destructor RtclRlinkConnect::~RtclRlinkConnect() {} //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_open(RtclArgs& args) { string path; if (!args.GetArg("?path", path)) return kERR; if (!args.AllDone()) return kERR; RerrMsg emsg; if (args.NOptMiss() == 0) { // open path if (!Obj().Open(path, emsg)) return args.Quit(emsg); } else { // open string name = Obj().IsOpen() ? Obj().Port()->Url().Url() : string(); args.SetResult(name); } return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_close(RtclArgs& args) { if (!args.AllDone()) return kERR; if (!Obj().IsOpen()) return args.Quit("-E: port not open"); Obj().Close(); return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_init(RtclArgs& args) { if (!args.AllDone()) return kERR; if (!Obj().IsOpen()) return args.Quit("-E: port not open"); if (Obj().LinkInitDone()) return args.Quit("-E: already initialized"); RerrMsg emsg; if (!Obj().LinkInit(emsg)) return args.Quit(emsg); return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_exec(RtclArgs& args) { static RtclNameSet optset("-rreg|-rblk|-wreg|-wblk|-labo|-attn|-init|" "-edata|-edone|-estat|" "-estaterr|-estatnak|-estattout|" "-print|-dump|-rlist"); Tcl_Interp* interp = args.Interp(); RlinkCommandList clist; string opt; uint16_t addr=0; vector vardata; vector varstat; string varprint; string vardump; string varlist; while (args.NextOpt(opt, optset)) { size_t lsize = clist.Size(); if (opt == "-rreg") { // -rreg addr ?varData ?varStat --- if (!GetAddr(args, addr)) return kERR; if (!GetVarName(args, "??varData", lsize, vardata)) return kERR; if (!GetVarName(args, "??varStat", lsize, varstat)) return kERR; clist.AddRreg(addr); } else if (opt == "-rblk") { // -rblk addr size ?varData ?varStat int32_t bsize=0; if (!GetAddr(args, addr)) return kERR; if (!args.GetArg("bsize", bsize, 1, Obj().BlockSizeMax())) return kERR; if (!GetVarName(args, "??varData", lsize, vardata)) return kERR; if (!GetVarName(args, "??varStat", lsize, varstat)) return kERR; clist.AddRblk(addr, (size_t) bsize); } else if (opt == "-wreg") { // -wreg addr data ?varStat ------- uint16_t data=0; if (!GetAddr(args, addr)) return kERR; if (!args.GetArg("data", data)) return kERR; if (!GetVarName(args, "??varStat", lsize, varstat)) return kERR; clist.AddWreg(addr, data); } else if (opt == "-wblk") { // -wblk addr block ?varStat ------ vector block; if (!GetAddr(args, addr)) return kERR; if (!args.GetArg("data", block, 1, Obj().BlockSizeMax())) return kERR; if (!GetVarName(args, "??varStat", lsize, varstat)) return kERR; clist.AddWblk(addr, block); } else if (opt == "-labo") { // -labo varData ?varStat --------- if (!GetVarName(args, "??varData", lsize, vardata)) return kERR; if (!GetVarName(args, "??varStat", lsize, varstat)) return kERR; clist.AddLabo(); } else if (opt == "-attn") { // -attn varData ?varStat --------- if (!GetVarName(args, "??varData", lsize, vardata)) return kERR; if (!GetVarName(args, "??varStat", lsize, varstat)) return kERR; clist.AddAttn(); } else if (opt == "-init") { // -init addr data ?varStat ------- uint16_t data=0; if (!GetAddr(args, addr)) return kERR; if (!args.GetArg("data", data)) return kERR; if (!GetVarName(args, "??varStat", lsize, varstat)) return kERR; clist.AddInit(addr, data); } else if (opt == "-edata") { // -edata data ?mask -------------- if (!ClistNonEmpty(args, clist)) return kERR; if (clist[lsize-1].Command() == RlinkCommand::kCmdRblk) { vector data; vector mask; size_t bsize = clist[lsize-1].BlockSize(); if (!args.GetArg("data", data, 0, bsize)) return kERR; if (!args.GetArg("??mask", mask, 0, bsize)) return kERR; clist.SetLastExpectBlock(data, mask); } else { uint16_t data=0; uint16_t mask=0xffff; if (!args.GetArg("data", data)) return kERR; if (!args.GetArg("??mask", mask)) return kERR; clist.SetLastExpectData(data, mask); } } else if (opt == "-edone") { // -edone done -------------------- if (!ClistNonEmpty(args, clist)) return kERR; uint16_t done=0; if (!args.GetArg("done", done)) return kERR; uint8_t cmd = clist[lsize-1].Command(); if (cmd == RlinkCommand::kCmdRblk || cmd == RlinkCommand::kCmdWblk) { clist.SetLastExpectDone(done); } else { return args.Quit("-E: -edone allowed only after -rblk,-wblk"); } } else if (opt == "-estat") { // -estat stat ?mask -------------- if (!ClistNonEmpty(args, clist)) return kERR; uint8_t stat=0; uint8_t mask=0xff; if (!args.GetArg("stat", stat)) return kERR; if (!args.GetArg("??mask", mask)) return kERR; clist.SetLastExpectStatus(stat, mask); } else if (opt == "-estaterr" || // -estaterr ---------------------- opt == "-estatnak" || // -estatnak ---------------------- opt == "-estattout") { // -estattout --------------------- if (!ClistNonEmpty(args, clist)) return kERR; uint8_t val = 0; uint8_t msk = RlinkCommand::kStat_M_RbTout | RlinkCommand::kStat_M_RbNak | RlinkCommand::kStat_M_RbErr; if (opt == "-estaterr") val = RlinkCommand::kStat_M_RbErr; if (opt == "-estatnak") val = RlinkCommand::kStat_M_RbNak; if (opt == "-estattout") val = RlinkCommand::kStat_M_RbTout; clist.SetLastExpectStatus(val, msk); } else if (opt == "-print") { // -print ?varRes ----------------- varprint = "-"; if (!args.GetArg("??varRes", varprint)) return kERR; } else if (opt == "-dump") { // -dump ?varRes ------------------ vardump = "-"; if (!args.GetArg("??varRes", vardump)) return kERR; } else if (opt == "-rlist") { // -rlist ?varRes ----------------- varlist = "-"; if (!args.GetArg("??varRes", varlist)) return kERR; } } // while (args.NextOpt(opt, optset)) int nact = 0; if (varprint == "-") nact += 1; if (vardump == "-") nact += 1; if (varlist == "-") nact += 1; if (nact > 1) return args.Quit( "-E: more that one of -print,-dump,-rlist without target variable found"); if (!args.AllDone()) return kERR; if (clist.Size() == 0) return kOK; RerrMsg emsg; if (!Obj().Exec(clist, emsg)) return args.Quit(emsg); for (size_t icmd=0; icmd retstat; RtclOPtr pele; switch (cmd.Command()) { case RlinkCommand::kCmdRreg: case RlinkCommand::kCmdAttn: case RlinkCommand::kCmdLabo: pres = Tcl_NewIntObj((int)cmd.Data()); break; case RlinkCommand::kCmdRblk: pres = Rtcl::NewListIntObj(cmd.Block()); break; } if(!Rtcl::SetVar(interp, vardata[icmd], pres)) return kERR; } if (icmdfirst); tpair[1] = Tcl_NewStringObj((it->second).c_str(),(it->second).length()); Tcl_ListObjAppendElement(nullptr, plist, Tcl_NewListObj(2, tpair)); } args.SetResult(plist); } } return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_errcnt(RtclArgs& args) { static RtclNameSet optset("-clear|-increment"); string opt; bool fclr = false; bool finc = false; while (args.NextOpt(opt, optset)) { if (opt == "-clear") fclr = true; if (opt == "-increment") finc = true; } if (!args.AllDone()) return kERR; if (finc) Obj().Context().IncErrorCount(); args.SetResult(int(Obj().Context().ErrorCount())); if (fclr) Obj().Context().ClearErrorCount(); return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_wtlam(RtclArgs& args) { double dtout; string rvn_apat; if (!args.GetArg("tout", dtout, 0.0)) return kERR; if (!args.GetArg("??varApat", rvn_apat)) return kERR; if (!args.AllDone()) return kERR; RerrMsg emsg; uint16_t apat = 0; Rtime twait; int irc = Obj().WaitAttn(Rtime(dtout), twait, apat, emsg); if (rvn_apat.length()) { if(!Rtcl::SetVar(args.Interp(), rvn_apat, Tcl_NewIntObj((int)apat))) return kERR; } if (irc == -2) { // IO error return args.Quit(emsg); } else if (irc == -1) { // timeout if (Obj().PrintLevel() >= 1) { RlogMsg lmsg(Obj().LogFile()); lmsg << "-- wtlam to=" << RosPrintf(dtout, "f", 0,3) << " FAIL timeout" << endl; Obj().Context().IncErrorCount(); args.SetResult(dtout); return kOK; } } if (Obj().PrintLevel() >= 3) { RlogMsg lmsg(Obj().LogFile()); lmsg << "-- wtlam apat=" << RosPrintf(apat,"x0",4); if (dtout == 0.) { lmsg << " to=0 harvest only"; } else { lmsg << " to=" << RosPrintf(dtout, "f", 0,3) << " T=" << RosPrintf(double(twait), "f", 0,3); } lmsg << " OK" << endl; } args.SetResult(double(twait)); return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_oob(RtclArgs& args) { static RtclNameSet optset("-rlmon|-rlbmon|-rbmon|-sbcntl|-sbdata"); string opt; uint16_t addr=0; uint16_t data=0; RerrMsg emsg; if (args.NextOpt(opt, optset)) { if (opt == "-rlmon") { // oob -rlmon (0|1) if (!args.GetArg("val", data, 1)) return kERR; if (!args.AllDone()) return kERR; addr = RlinkConnect:: kSBCNTL_V_RLMON; // rlmon enable bit if (!Obj().SndOob(0x00, (addr<<8)+data, emsg)) return args.Quit(emsg); } else if (opt == "-rlbmon") { // oob -rlbmon (0|1) if (!args.GetArg("val", data, 1)) return kERR; if (!args.AllDone()) return kERR; addr = RlinkConnect:: kSBCNTL_V_RLBMON; // rlbmon enable bit if (!Obj().SndOob(0x00, (addr<<8)+data, emsg)) return args.Quit(emsg); } else if (opt == "-rbmon") { // oob -rbmon (0|1) if (!args.GetArg("val", data, 1)) return kERR; if (!args.AllDone()) return kERR; addr = RlinkConnect:: kSBCNTL_V_RBMON; // rbmon enable bit if (!Obj().SndOob(0x00, (addr<<8)+data, emsg)) return args.Quit(emsg); } else if (opt == "-sbcntl") { // oob -sbcntl bit (0|1) if (!args.GetArg("bit", addr, 15)) return kERR; if (!args.GetArg("val", data, 1)) return kERR; if (!args.AllDone()) return kERR; if (!Obj().SndOob(0x00, (addr<<8)+data, emsg)) return args.Quit(emsg); } else if (opt == "-sbdata") { // oob -sbdata addr val if (!args.GetArg("bit", addr, 0x0ff)) return kERR; if (!args.GetArg("val", data)) return kERR; if (!args.AllDone()) return kERR; if (!Obj().SndOob(addr, data, emsg)) return args.Quit(emsg); } } else { return args.Quit( "-E: missing option, one of -rlmon,-rbmon,-sbcntl,-sbdata"); } return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_rawread(RtclArgs& args) { return RtclRlinkPort::DoRawRead(args, Obj().Port()); } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_rawrblk(RtclArgs& args) { size_t errcnt = 0; int rc = RtclRlinkPort::DoRawRblk(args, Obj().Port(), errcnt); Obj().Context().IncErrorCount(errcnt); return rc; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_rawwblk(RtclArgs& args) { return RtclRlinkPort::DoRawWblk(args, Obj().Port()); } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_stats(RtclArgs& args) { RtclStats::Context cntx; if (!RtclStats::GetArgs(args, cntx)) return kERR; if (!RtclStats::Collect(args, cntx, Obj().Stats())) return kERR; if (!RtclStats::Collect(args, cntx, Obj().SndStats())) return kERR; if (!RtclStats::Collect(args, cntx, Obj().RcvStats())) return kERR; if (Obj().Port()) { if (!RtclStats::Collect(args, cntx, Obj().Port()->Stats())) return kERR; } return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_log(RtclArgs& args) { static RtclNameSet optset("-bare|-info|-warn|-error|-fatal"); string opt; bool fbare = false; char tag = 0; while (args.NextOpt(opt, optset)) { if (opt == "-bare") fbare = true; if (opt == "-info") tag = 'I'; if (opt == "-warn") tag = 'W'; if (opt == "-error") tag = 'E'; if (opt == "-fatal") tag = 'F'; } string msg; if (!args.GetArg("msg", msg)) return kERR; if (!args.AllDone()) return kERR; if (Obj().PrintLevel() != 0 || Obj().DumpLevel() != 0 || Obj().TraceLevel() != 0) { if (tag || fbare) { Obj().LogFile().Write(msg, tag); } else { Obj().LogFile().Write(string("# ") + msg); } } return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_print(RtclArgs& args) { if (!args.AllDone()) return kERR; ostringstream sos; Obj().Print(sos); args.SetResult(sos); return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_dump(RtclArgs& args) { int detail=0; if (!GetArgsDump(args, detail)) return kERR; if (!args.AllDone()) return kERR; ostringstream sos; Obj().Dump(sos, 0, "", detail); args.SetResult(sos); return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_get(RtclArgs& args) { // synchronize with server thread (really needed ??) boost::lock_guard lock(Obj()); return fGets.M_get(args); } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_set(RtclArgs& args) { // synchronize with server thread (really needed ??) boost::lock_guard lock(Obj()); return fSets.M_set(args); } //------------------------------------------+----------------------------------- //! FIXME_docs int RtclRlinkConnect::M_default(RtclArgs& args) { if (!args.AllDone()) return kERR; ostringstream sos; sos << "print base: " << "addr " << RosPrintf(Obj().LogBaseAddr(), "d", 2) << " data " << RosPrintf(Obj().LogBaseData(), "d", 2) << " stat " << RosPrintf(Obj().LogBaseStat(), "d", 2) << endl; sos << "logfile: " << Obj().LogFile().Name() << " printlevel " << Obj().PrintLevel() << " dumplevel " << Obj().DumpLevel(); args.AppendResultLines(sos); return kOK; } //------------------------------------------+----------------------------------- //! FIXME_docs bool RtclRlinkConnect::GetAddr(RtclArgs& args, uint16_t& addr) { Tcl_Obj* pobj=0; if (!args.GetArg("addr", pobj)) return kERR; int tstint=0; // if a number is given.. if (Tcl_GetIntFromObj(nullptr, pobj, &tstint) == kOK) { if (tstint >= 0 && tstint <= 0xffff) { addr = (uint16_t)tstint; } else { args.AppendResult("-E: value '", Tcl_GetString(pobj), "' for 'addr' out of range 0...0xffff", nullptr); return false; } // if a name is given } else { string name(Tcl_GetString(pobj)); uint16_t tstaddr=0; if (Obj().AddrMap().Find(name, tstaddr)) { addr = tstaddr; } else { args.AppendResult("-E: no address mapping known for '", Tcl_GetString(pobj), "'", nullptr); return false; } } return true; } //------------------------------------------+----------------------------------- //! FIXME_docs bool RtclRlinkConnect::GetVarName(RtclArgs& args, const char* argname, size_t nind, std::vector& varname) { while (varname.size() < nind+1) varname.push_back(string()); string name; if (!args.GetArg(argname, name)) return false; if (name.length()) { // if variable defined char c = name[0]; if (isdigit(c) || c=='+' || c=='-' ) { // check for mistaken number args.AppendResult("-E: invalid variable name '", name.c_str(), "': looks like a number", nullptr); return false; } } varname[nind] = name; return true; } //------------------------------------------+----------------------------------- //! FIXME_docs bool RtclRlinkConnect::ConfigBase(RtclArgs& args, uint32_t& base) { uint32_t tmp = base; if (!args.Config("??base", tmp, 16, 2)) return false; if (tmp != base && tmp != 2 && tmp !=8 && tmp != 16) { args.AppendResult("-E: base must be 2, 8, or 16, found '", args.PeekArgString(-1), "'", nullptr); return false; } base = tmp; return true; } //------------------------------------------+----------------------------------- //! FIXME_docs bool RtclRlinkConnect::ClistNonEmpty(RtclArgs& args, const RlinkCommandList& clist) { if (clist.Size() == 0) { args.AppendResult("-E: -edata, -edone, or -estat " "not allowed on empty command list", nullptr); return false; } return true; } } // end namespace Retro