w11 - cpp 0.794
Backend server for Rlink and w11
Loading...
Searching...
No Matches
Rw11UnitTerm.cpp
Go to the documentation of this file.
1// $Id: Rw11UnitTerm.cpp 1186 2019-07-12 17:49:59Z mueller $
2// SPDX-License-Identifier: GPL-3.0-or-later
3// Copyright 2013-2019 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4//
5// Revision History:
6// Date Rev Version Comment
7// 2019-05-18 1150 1.2 add detailed stats and StatInc{Rx,Tx}
8// 2018-12-19 1090 1.1.7 use RosPrintf(bool)
9// 2018-12-17 1085 1.1.6 use std::lock_guard instead of boost
10// 2018-12-14 1081 1.1.5 use std::bind instead of boost
11// 2018-12-09 1080 1.1.4 use HasVirt(); Virt() returns ref
12// 2018-12-01 1076 1.1.3 use unique_ptr
13// 2017-04-07 868 1.1.2 Dump(): add detail arg
14// 2017-02-25 855 1.1.1 RcvNext() --> RcvQueueNext(); WakeupCntl() now pure
15// 2013-05-03 515 1.1 use AttachDone(),DetachCleanup(),DetachDone()
16// 2013-04-13 504 1.0 Initial version
17// 2013-02-19 490 0.1 First draft
18// ---------------------------------------------------------------------------
19
24#include <functional>
25
27#include "librtools/RosFill.hpp"
30
31#include "Rw11UnitTerm.hpp"
32
33using namespace std;
34using namespace std::placeholders;
35
41// all method definitions in namespace Retro
42namespace Retro {
43
44//------------------------------------------+-----------------------------------
46
48 : Rw11UnitVirt<Rw11VirtTerm>(pcntl, index),
49 fTo7bit(false),
50 fToEnpc(false),
51 fTi7bit(false),
52 fRcvQueue(),
53 fLogFname(),
54 fLogStream(),
55 fLogOptCrlf(false),
56 fLogCrPend(false),
57 fLogLfLast(false)
58{
59 fStats.Define(kStatNPreAttDrop, "NPreAttDrop",
60 "snd bytes dropped prior attach");
61 fStats.Define(kStatNRxFerr, "NRxFerr", "rx frame error");
62 fStats.Define(kStatNRxChar, "NRxChar", "rx char (no ferr)");
63 fStats.Define(kStatNRxNull, "NRxNull", "rx null char");
64 fStats.Define(kStatNRx8bit, "NRx8bit", "rx with bit 8 set");
65 fStats.Define(kStatNRxLine, "NRxline", "rx lines (CR)");
66 fStats.Define(kStatNTxFerr, "NTxFerr", "tx frame error");
67 fStats.Define(kStatNTxChar, "NTxChar", "tx char (no ferr)");
68 fStats.Define(kStatNTxNull, "NTxNull", "tx null char");
69 fStats.Define(kStatNTx8bit, "NTx8bit", "tx with bit 8 set");
70 fStats.Define(kStatNTxLine, "NTxline", "tx lines (LF)");
71}
72
73//------------------------------------------+-----------------------------------
75
77{}
78
79//------------------------------------------+-----------------------------------
81
82const std::string& Rw11UnitTerm::ChannelId() const
83{
84 if (HasVirt()) return Virt().ChannelId();
85 static string nil;
86 return nil;
87}
88
89//------------------------------------------+-----------------------------------
91
92void Rw11UnitTerm::SetLog(const std::string& fname)
93{
94 if (fLogStream.is_open()) {
95 if (fLogCrPend) fLogStream << "\r";
96 fLogCrPend = false;
97 fLogStream.close();
98 }
99
100 fLogFname.clear();
101 if (fname.length() == 0) return;
102
103 RparseUrl purl;
104 RerrMsg emsg;
105 if (!purl.Set(fname, "|app|bck=|crlf|", emsg))
106 throw Rexception(emsg);
107 if (!Rtools::CreateBackupFile(purl, emsg))
108 throw Rexception(emsg);
109
110 ios_base::openmode mode = ios_base::out;
111 if (purl.FindOpt("app")) mode |= ios_base::app;
112
113 fLogStream.open(purl.Path(), mode);
114 if (!fLogStream.is_open()) {
115 throw Rexception("Rw11UnitTerm::SetLog",
116 string("failed to open '")+purl.Path()+"'");
117 }
118
119 fLogFname = fname;
120 fLogOptCrlf = purl.FindOpt("crlf");
121 fLogCrPend = false;
122 fLogLfLast = false;
123
124 return;
125}
126
127//------------------------------------------+-----------------------------------
129
130void Rw11UnitTerm::StatIncRx(uint8_t ichr, bool ferr)
131{
132 if (ferr) {
134 } else {
136 if (ichr == 0) fStats.Inc(kStatNRxNull);
137 if (ichr & 0x80) fStats.Inc(kStatNRx8bit);
138 if (fTi7bit) ichr &= 0x80;
139 if (ichr == '\r') fStats.Inc(kStatNRxLine); // count CR
140 }
141 return;
142}
143
144//------------------------------------------+-----------------------------------
146
147void Rw11UnitTerm::StatIncTx(uint8_t ochr, bool ferr)
148{
149 if (ferr) {
151 } else {
153 if (ochr == 0) fStats.Inc(kStatNTxNull);
154 if (ochr & 0x80) fStats.Inc(kStatNTx8bit);
155 if (fTo7bit) ochr &= 0x80;
156 if (ochr == '\n') fStats.Inc(kStatNTxLine); // count LF
157 }
158 return;
159}
160
161//------------------------------------------+-----------------------------------
163
165{
166 if (RcvQueueEmpty()) return 0;
167 uint8_t ochr = fRcvQueue.front();
168 fRcvQueue.pop_front();
169 return ochr;
170}
171
172//------------------------------------------+-----------------------------------
174
175size_t Rw11UnitTerm::Rcv(uint8_t* buf, size_t count)
176{
177 uint8_t* p = buf;
178 for (size_t i=0; i<count && !fRcvQueue.empty(); i++) {
179 *p++ = fRcvQueue.front();
180 fRcvQueue.pop_front();
181 }
182 return p - buf;
183}
184
185//------------------------------------------+-----------------------------------
187
188bool Rw11UnitTerm::Snd(const uint8_t* buf, size_t count)
189{
190 bool ok = true;
191 vector<uint8_t> bufmod;
192 const uint8_t* bufout = buf;
193 size_t bufcnt = count;
194
195 if (fTo7bit || fToEnpc) {
196 for (size_t i=0; i<count; i++) {
197 uint8_t ochr = buf[i];
198 if (fTo7bit) ochr &= 0177;
199 if (fToEnpc) {
200 if ((ochr>=040 && ochr<177) ||
201 ochr=='\t' || ochr=='\n' || ochr=='\r') {
202 bufmod.push_back(ochr);
203 } else {
204 if (ochr != 0) {
205 bufmod.push_back('<');
206 bufmod.push_back('0' + ((ochr>>6)&07) );
207 bufmod.push_back('0' + ((ochr>>3)&07) );
208 bufmod.push_back('0' + (ochr &07) );
209 bufmod.push_back('>');
210 }
211 }
212
213 } else {
214 bufmod.push_back(ochr);
215 }
216 }
217 bufout = bufmod.data();
218 bufcnt = bufmod.size();
219 }
220
221 if (fLogStream.is_open()) {
222 for (size_t i=0; i<bufcnt; i++) {
223 uint8_t ochr = bufout[i];
224 // the purpose of the 'crlf' filter is to map
225 // \r\n -> \n
226 // \r\r\n -> \n (any number of \r)
227 // \n\r -> \n
228 // \n\r\r -> \n (any number of \r)
229 // and to ignore \0 chars
230 if (fLogOptCrlf) { // crlf filtering on
231 if (ochr == 0) continue; // ignore \0 chars
232 if (fLogCrPend) {
233 if (ochr == '\r') continue; // collapes multiple \r
234 if (ochr != '\n') fLogStream << '\r'; // log \r if not followed by \n
235 fLogCrPend = false;
236 }
237 if (ochr == '\r') { // \r seen
238 fLogCrPend = !fLogLfLast; // remember \r if last wasn't \n
239 continue;
240 }
241 }
242 fLogStream << char(ochr);
243 fLogLfLast = (ochr == '\n');
244 }
245 }
246
247 if (HasVirt()) { // if virtual device attached
248 RerrMsg emsg;
249 ok = Virt().Snd(bufout, bufcnt, emsg);
250 // FIXME_code: handler errors
251
252 } else { // no virtual device attached
253 if (Name() == "tta0") { // is it main console ?
254 for (size_t i=0; i<bufcnt; i++) { // than print to stdout
255 cout << char(bufout[i]) << flush;
256 }
257 } else { // otherwise discard
258 fStats.Inc(kStatNPreAttDrop, double(bufcnt)); // and count at least...
259 }
260 }
261 return ok;
262}
263
264
265//------------------------------------------+-----------------------------------
267
268bool Rw11UnitTerm::RcvCallback(const uint8_t* buf, size_t count)
269{
270 // lock connect to protect rxqueue
271 lock_guard<RlinkConnect> lock(Connect());
272
273 bool que_empty_old = fRcvQueue.empty();
274 for (size_t i=0; i<count; i++) {
275 uint8_t ichr = buf[i];
276 if (fTi7bit) ichr &= 0177;
277 fRcvQueue.push_back(ichr);
278 }
279 bool que_empty_new = fRcvQueue.empty();
280 if (que_empty_old && !que_empty_new) WakeupCntl();
281 return true;
282}
283
284//------------------------------------------+-----------------------------------
286
287void Rw11UnitTerm::Dump(std::ostream& os, int ind, const char* text,
288 int detail) const
289{
290 RosFill bl(ind);
291 os << bl << (text?text:"--") << "Rw11UnitTerm @ " << this << endl;
292
293 os << bl << " fTo7bit: " << RosPrintf(fTo7bit) << endl;
294 os << bl << " fToEnpc: " << RosPrintf(fToEnpc) << endl;
295 os << bl << " fTi7bit: " << RosPrintf(fTi7bit) << endl;
296 {
297 lock_guard<RlinkConnect> lock(Connect());
298 size_t size = fRcvQueue.size();
299 os << bl << " fRcvQueue.size: " << fRcvQueue.size() << endl;
300 if (size > 0) {
301 os << bl << " fRcvQueue: \"";
302 size_t ocount = 0;
303 for (size_t i=0; i<size; i++) {
304 if (ocount >= 50) {
305 os << "...";
306 break;
307 }
308 uint8_t byt = fRcvQueue[i];
309 if (byt >= 040 && byt <= 0176) {
310 os << char(byt);
311 ocount += 1;
312 } else {
313 os << "<" << RosPrintf(byt,"o0",3) << ">";
314 ocount += 5;
315 }
316 }
317 os << "\"" << endl;
318 }
319 }
320
321 os << bl << " fLogFname: " << fLogFname << endl;
322 os << bl << " fLogStream.is_open: " << RosPrintf(fLogStream.is_open())<<endl;
323 os << bl << " fLogOptCrlf: " << RosPrintf(fLogOptCrlf) << endl;
324 os << bl << " fLogCrPend: " << RosPrintf(fLogCrPend) << endl;
325 os << bl << " fLogLfLast: " << RosPrintf(fLogLfLast) << endl;
326
327 Rw11UnitVirt<Rw11VirtTerm>::Dump(os, ind, " ^", detail);
328 return;
329}
330
331//------------------------------------------+-----------------------------------
333
335{
336 Virt().SetupRcvCallback(std::bind(&Rw11UnitTerm::RcvCallback, this, _1, _2));
337 return;
338}
339
340
341} // end namespace Retro
FIXME_docs.
Definition: RerrMsg.hpp:25
FIXME_docs.
Definition: Rexception.hpp:29
I/O appicator to generate fill characters.
Definition: RosFill.hpp:24
FIXME_docs.
Definition: RparseUrl.hpp:27
bool FindOpt(const std::string &name) const
FIXME_docs.
Definition: RparseUrl.cpp:196
bool Set(const std::string &url, const std::string &optlist, RerrMsg &emsg)
FIXME_docs.
Definition: RparseUrl.cpp:55
const std::string & Path() const
FIXME_docs.
Definition: RparseUrl.ipp:45
void Inc(size_t ind, double val=1.)
FIXME_docs.
Definition: Rstats.ipp:29
void Define(size_t ind, const std::string &name, const std::string &text)
FIXME_docs.
Definition: Rstats.cpp:72
FIXME_docs.
Definition: Rw11Cntl.hpp:42
virtual void Dump(std::ostream &os, int ind=0, const char *text=0, int detail=0) const
FIXME_docs.
void StatIncTx(uint8_t ochr, bool ferr=false)
FIXME_docs.
bool fTi7bit
discard parity bit on input
virtual void AttachDone()
FIXME_docs.
virtual bool RcvQueueEmpty()
FIXME_docs.
virtual bool Snd(const uint8_t *buf, size_t count)
FIXME_docs.
bool fLogOptCrlf
log file: crlf option given
virtual bool RcvCallback(const uint8_t *buf, size_t count)
FIXME_docs.
std::ofstream fLogStream
log file stream
virtual uint8_t RcvQueueNext()
FIXME_docs.
bool fLogCrPend
log file: cr pending
bool fTo7bit
discard parity bit on output
virtual void WakeupCntl()=0
std::string fLogFname
log file name
@ kStatNTx8bit
tx with bit 8 set
@ kStatNPreAttDrop
dropped prior to attach
@ kStatNRxFerr
rx frame error
@ kStatNRxLine
rx lines (CR)
@ kStatNRx8bit
rx with bit 8 set
@ kStatNTxFerr
tx frame error
@ kStatNTxNull
tx null char
@ kStatNTxLine
tx lines (LF)
@ kStatNRxNull
rx null char
@ kStatNTxChar
tx char (no ferr)
@ kStatNRxChar
rx char (no ferr)
bool fToEnpc
escape non-printables on output
void SetLog(const std::string &fname)
FIXME_docs.
~Rw11UnitTerm()
Destructor.
void StatIncRx(uint8_t ichr, bool ferr=false)
FIXME_docs.
Rw11UnitTerm(Rw11Cntl *pcntl, size_t index)
Constructor.
std::deque< uint8_t > fRcvQueue
input queue
virtual size_t Rcv(uint8_t *buf, size_t count)
FIXME_docs.
bool fLogLfLast
log file: lf was last char
const std::string & ChannelId() const
FIXME_docs.
Implemenation (inline) of Rw11UnitVirt.
Rw11VirtTerm & Virt()
FIXME_docs.
virtual void Dump(std::ostream &os, int ind=0, const char *text=0, int detail=0) const
FIXME_docs.
bool HasVirt() const
FIXME_docs.
Rstats fStats
statistics
Definition: Rw11Unit.hpp:90
std::string Name() const
FIXME_docs.
Definition: Rw11Unit.ipp:31
RlinkConnect & Connect() const
FIXME_docs.
Definition: Rw11Unit.ipp:88
void SetupRcvCallback(rcvcbfo_t &&rcvcbfo)
FIXME_docs.
virtual bool Snd(const uint8_t *data, size_t count, RerrMsg &emsg)=0
virtual const std::string & ChannelId() const
FIXME_docs.
RosPrintfS< bool > RosPrintf(bool value, const char *form=0, int width=0, int prec=0)
Creates a print object for the formatted output of a bool value.
Definition: RosPrintf.ipp:38
bool CreateBackupFile(const std::string &fname, size_t nbackup, RerrMsg &emsg)
FIXME_docs.
Definition: Rtools.cpp:98
Declaration of class ReventLoop.
Definition: ReventLoop.cpp:47