1
0
mirror of https://github.com/wfjm/w11.git synced 2026-02-10 02:20:29 +00:00
Files
wfjm.w11/tools/src/librlinktpp/RtclAttnShuttle.cpp
2018-12-22 09:20:02 +01:00

174 lines
5.1 KiB
C++

// $Id: RtclAttnShuttle.cpp 1089 2018-12-19 10:45:41Z mueller $
//
// Copyright 2013-2018 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
//
// 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-12-18 1089 1.1.3 use c++ style casts
// 2018-12-15 1082 1.1.2 use lambda instead of bind
// 2018-10-27 1059 1.1.1 coverity fixup (uncaught exception in dtor)
// 2014-12-30 625 1.1 adopt to Rlink V4 attn logic
// 2014-11-08 602 1.0.3 cast int first to ptrdiff_t, than to ClientData
// 2014-08-22 584 1.0.2 use nullptr
// 2013-05-20 521 1.0.1 Setup proper Tcl channel options
// 2013-03-01 493 1.0 Initial version
// 2013-01-12 475 0.5 First draft
// ---------------------------------------------------------------------------
/*!
\file
\brief Implemenation of class RtclAttnShuttle.
*/
#include <unistd.h>
#include <errno.h>
#include "librtools/Rexception.hpp"
#include "librtools/Rtools.hpp"
#include "RtclAttnShuttle.hpp"
using namespace std;
/*!
\class Retro::RtclAttnShuttle
\brief FIXME_docs
*/
// all method definitions in namespace Retro
namespace Retro {
//------------------------------------------+-----------------------------------
//! constructor
RtclAttnShuttle::RtclAttnShuttle(uint16_t mask, Tcl_Obj* pobj)
: fpServ(nullptr),
fpInterp(nullptr),
fFdPipeRead(-1),
fFdPipeWrite(-1),
fShuttleChn(0),
fMask(mask),
fpScript(pobj)
{
int pipefd[2];
int irc = ::pipe(pipefd);
if (irc < 0)
throw Rexception("RtclAttnShuttle::<ctor>", "pipe() failed: ", errno);
fFdPipeRead = pipefd[0];
fFdPipeWrite = pipefd[1];
}
//------------------------------------------+-----------------------------------
//! Destructor
RtclAttnShuttle::~RtclAttnShuttle()
{
Rtools::Catch2Cerr(__func__, [this](){ Remove();} );
::close(fFdPipeWrite);
::close(fFdPipeRead);
}
//------------------------------------------+-----------------------------------
//! FIXME_docs
void RtclAttnShuttle::Add(RlinkServer* pserv, Tcl_Interp* interp)
{
// connect to RlinkServer
pserv->AddAttnHandler([this](RlinkServer::AttnArgs& args)
{ return AttnHandler(args); },
fMask, this);
fpServ = pserv;
// connect to Tcl
// cast first to ptrdiff_t to promote to proper int size
fShuttleChn = Tcl_MakeFileChannel(reinterpret_cast<ClientData>(fFdPipeRead),
TCL_READABLE);
Tcl_SetChannelOption(nullptr, fShuttleChn, "-buffersize", "64");
Tcl_SetChannelOption(nullptr, fShuttleChn, "-encoding", "binary");
Tcl_SetChannelOption(nullptr, fShuttleChn, "-translation", "binary");
Tcl_CreateChannelHandler(fShuttleChn, TCL_READABLE,
reinterpret_cast<Tcl_FileProc*>(ThunkTclChannelHandler),
reinterpret_cast<ClientData>(this));
fpInterp = interp;
return;
}
//------------------------------------------+-----------------------------------
//! FIXME_docs
void RtclAttnShuttle::Remove()
{
// disconnect from RlinkServer
if (fpServ) {
fpServ->RemoveAttnHandler(fMask, this);
fpServ = nullptr;
}
// disconnect from Tcl
if (fpInterp) {
Tcl_DeleteChannelHandler(fShuttleChn,
reinterpret_cast<Tcl_FileProc*>(ThunkTclChannelHandler),
reinterpret_cast<ClientData>(this));
Tcl_Close(fpInterp, fShuttleChn);
fpInterp = nullptr;
}
return;
}
//------------------------------------------+-----------------------------------
//! FIXME_docs
int RtclAttnShuttle::AttnHandler(RlinkServer::AttnArgs& args)
{
fpServ->GetAttnInfo(args);
uint16_t apat = args.fAttnPatt & args.fAttnMask;
int irc = ::write(fFdPipeWrite, &apat, sizeof(apat));
if (irc < 0)
throw Rexception("RtclAttnShuttle::AttnHandler()",
"write() failed: ", errno);
return 0;
}
//------------------------------------------+-----------------------------------
//! FIXME_docs
void RtclAttnShuttle::TclChannelHandler(int /*mask*/)
{
uint16_t apat;
Tcl_ReadRaw(fShuttleChn, reinterpret_cast<char*>(&apat), sizeof(apat));
// FIXME_code: handle return code
Tcl_SetVar2Ex(fpInterp, "Rlink_attnbits", nullptr,
Tcl_NewIntObj(int(apat)), 0);
// FIXME_code: handle return code
Tcl_EvalObjEx(fpInterp, fpScript, TCL_EVAL_GLOBAL);
// FIXME_code: handle return code
return;
}
//------------------------------------------+-----------------------------------
//! FIXME_docs
void RtclAttnShuttle::ThunkTclChannelHandler(ClientData cdata, int mask)
{
reinterpret_cast<RtclAttnShuttle*>(cdata)->TclChannelHandler(mask);
return;
}
} // end namespace Retro