1 #ifndef arq_H
2 #define arq_H
3 
4 // ----------------------------------------------------------------------------
5 // arq module arq.h
6 // Copyright (c) 2007-2009, Dave Freese, W1HKJ
7 //
8 //
9 // This file is part of fldigi.
10 //
11 // Fldigi is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // Fldigi is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
23 // ----------------------------------------------------------------------------
24 
25 //	link layer spec for fldigi_arq
26 //
27 //	generic Frame format:
28 //	   <SOH>dcl[info])12EF<EOT|SOH>
29 //		|	||| |     |    |
30 //		|	||| |     |    +--ASCII <SOH> or <EOT> (0x04) character
31 //		|	||| |     +-------checksum (4xAlphaNum)
32 //		|	||| +-------------Payload (1 ... 2^N chars, N 4, 5, 6, 7 8)
33 //		|	||+---------------Block type
34 //		|	|+----------------Stream id
35 //		|	+-----------------Protocol version number
36 //		+---------------------ASCII <SOH> (0x01) character
37 // BLOCKSIZE = 2^n
38 //
39 
40 #include <string>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <iostream>
44 #include <vector>
45 #include <list>
46 #include <cctype>
47 
48 #include <FL/Fl.H>
49 
50 extern int idtimer;
51 
52 #define DEBUG
53 
54 #define arq_Version "arq 0.1"
55 //=====================================================================
56 // following Block Types are defined in K9PS ARQ Protocol specification
57 #define IDENT		'i'
58 #define CONREQ		'c'
59 #define CONACK		'k'
60 #define REFUSED		'r'
61 #define DISREQ		'd'
62 #define STATUS		's'
63 #define POLL		'p'
64 #define FMTFAIL		'f'
65 // following Block Types are extensions to the K9PS specification
66 #define _ABORT		'a'
67 #define _ACKABORT   'o'
68 #define _DISACK		'b'
69 #define _UNPROTO	'u'
70 #define _TALK	    't'
71 //=====================================================================
72 #define SOH			0X01
73 #define STX			0X02
74 #define ACK			0X06
75 #define SUB			0X1A
76 #define EOT			0X04
77 //=====================================================================
78 //ARQ defaults
79 #define	MAXHEADERS  	8	// Max. number of missing blocks
80 #define MAXCOUNT		64  // DO NOT CHANGE THIS CONSTANT
81 #define EXPONENT		7	// Bufferlength = 2 ^ EXPONENT = 128
82 //=====================================================================
83 //link timing defaults
84 #define	RETRIES			5
85 #define RETRYTIME		10000	// # milliseconds between retries
86 #define TXDELAY			500     // # milliseconds from xmt to rcv
87 #define TIMEOUT			60000	// # milliseconds before TIMED OUT
88 #define ARQLOOPTIME		100		// # msec for loop timing
89 //=====================================================================
90 //link states
91 enum LINK_STATES {
92 	DOWN = 0,
93 	TIMEDOUT,
94 	ABORT,
95 	ARQ_CONNECTING,
96 	ARQ_CONNECTED,
97 	WAITING,
98 	WAITFORACK,
99 	DISCONNECT,
100 	DISCONNECTING,
101 	ABORTING,
102 	STOPPED
103 };
104 
105 //#define DOWN			0
106 //#define TIMEDOUT		1
107 //#define ABORT			3
108 //#define ARQ_CONNECTING	4
109 //#define ARQ_CONNECTED	5
110 //#define WAITING			6
111 //#define WAITFORACK		7
112 //#define DISCONNECT		8
113 //#define DISCONNECTING	9
114 //#define ABORTING		10
115 
116 #define SENDING       0x80;
117 
118 //=====================================================================
119 
120 extern char *ARQASCII[];
121 
122 // crc 16 cycle redundancy check sum for data block integrity
123 
124 class Ccrc16 {
125 private:
126 	unsigned int crcval;
127 	char ss[5];
128 public:
Ccrc16()129 	Ccrc16() { crcval = 0xFFFF; }
~Ccrc16()130 	~Ccrc16() {};
reset()131 	void reset() { crcval = 0xFFFF;}
val()132 	unsigned int val() {return crcval;}
sval()133 	std::string sval() {
134 		snprintf(ss, sizeof(ss), "%04X", crcval);
135 		return ss;
136 	}
update(char c)137 	void update(char c) {
138 		crcval ^= c & 255;
139         for (int i = 0; i < 8; ++i) {
140             if (crcval & 1)
141                 crcval = (crcval >> 1) ^ 0xA001;
142             else
143                 crcval = (crcval >> 1);
144         }
145 	}
crc16(char c)146 	unsigned int crc16(char c) {
147 		update(c);
148 		return crcval;
149 	}
crc16(std::string s)150 	unsigned int crc16(std::string s) {
151 		reset();
152 		for (size_t i = 0; i < s.length(); i++)
153 			update(s[i]);
154 		return crcval;
155 	}
scrc16(std::string s)156 	std::string scrc16(std::string s) {
157 		crc16(s);
158 		return sval();
159 	}
160 };
161 
162 // text block; block # and std::string of text
163 class cTxtBlk {
164 private:
165 	int number;
166 	std::string txt;
167 public:
cTxtBlk()168 	cTxtBlk() {number = -1; txt = "";}
cTxtBlk(int n,std::string text)169 	cTxtBlk(int n, std::string text) { number = n; txt = text; }
~cTxtBlk()170 	~cTxtBlk() {}
nbr(int n)171 	void nbr(int n) { number = n;}
nbr()172 	int nbr() { return number; }
text()173 	std::string text() { return txt; }
text(std::string t)174 	void text(std::string t) { txt = t;}
175 	bool operator <(const cTxtBlk &b)const { return number < b.number; }
176 	bool operator ==(const cTxtBlk b)const { return number == b.number; }
177 };
178 
179 
180 class arq {
181 
182 private:
183 	bool	arqstop;
184 
185 	std::string	MyCall;
186 	std::string	UrCall;
187 
188 	std::string	Header;
189 	std::string	Frame;
190 	std::string	Payload;
191 	std::string	rcvPayload;
192 
193 	std::string	logfile;
194 
195 	char	MyStreamID;
196 	char	UrStreamID;
197 
198 	char	MyBlockLengthChar;
199 	char	UrBlockLengthChar;
200 	char	BlockNumberChar;
201 	char	fID;
202 	int		blknbr;
203 
204 // queues //
205 	std::string	TxTextQueue;			// Text out to mail engine
206 	std::string	TxPlainTextQueue;		// plain text transmit queu
207 	std::string	RxTextQueue;			// Text in from mail engine
208 	std::string	RxFrameQueue;
209 	char	lastRxChar;
210 	bool	TXflag;
211 
212 	int		Bufferlength;
213 	int		maxheaders;
214 	int		exponent;
215 
216 // status variables
217 	int 	payloadlength;	// Average length of payload received
218 	int	totalRx;		// total number of frames received
219 	int	totalTx;		// total number of frames transmitted
220 	int	nbrbadRx;		// number with crc errors
221 	int	nbrbadTx;		// total number of repeats required
222 //	int 	max_idle;		// Dynamic timing slot initial value
223 	int	SessionNumber;
224 	bool	PollOK;			// used for status handshake
225 	bool	wrappedFlag;	// set true if missing blocks bit count
226 							// has wrapped around
227 	int	retrytime;
228 	int	RetryTime;
229 	int	retries;
230 	int	Retries;
231 	int	timeout;
232 	int	Timeout;
233 	int	tx2txdelay;
234 	int	TxDelay;
235 	int	loopcount;
236 	int	_idtimer;
237 
238 	int	baseRetryTime;
239 	int	baseTimeout;
240 	int	baseRetries;
241 
242 	bool	immediate;
243 	bool    primary;
244 
245 	Ccrc16	framecrc;
246 
247 // My status
248 	int		Firstsent;					// First Header  I sent last turn
249 	int		LastHeader;					// Last Header I sent last turn
250 	int		Lastqueued;					// Last Header in static send queue
251 
252 	int		EndHeader;					// Last I received o.k.
253 	int		GoodHeader;					// Last Header received consecutively
254 	int		blkcount;
255 	int		Blocks2Send;				// number of blocks at beginning of Tx
256 
257 	std::vector<int>	MyMissing;		// missing Rx blocks
258 	std::string MissingRxBlocks;
259 	std::vector<cTxtBlk> RxPending;		// RxPending Rx blocks (not consecutive)
260 
261 	std::list<cTxtBlk> TxBlocks;		// fifo of transmit buffers
262 	std::list<cTxtBlk> TxMissing;		// fifo of sent; RxPending Status report
263 	std::list<cTxtBlk> TxPending;		// fifo of transmitted buffers pending print
264 
265 // Ur status
266 	int		UrGoodHeader;				// Other station's Good Header
267 	int		UrLastHeader;				// Other station's Header last sent
268 	int		UrEndHeader;				// Other station's last received Header
269 	std::vector<int>	UrMissing;		// Other station's missing Headers
270 
271 	int		LinkState;					// status of ARQ link
272 	int		Sending;
273 
274 	bool	bABORT;
275 
276 // Link quality for sending *** used for testing only !! ***
277 //	double	sendquality;
278 
279 	void	reset();
280 	void	resetTx();
281 	void	resetRx();
282 	int     rtry();
283 
284 	void	setBufferlength();
285 
286 	void	checkblocks();
287 	std::string	upcase(std::string s);
288 	void	newblocknumber();
289 	void	newHeader();
290 	void	IdHeader();
291 	void	UnkHeader();
292 
293 	void	connectFrame();
294 	void	disackFrame();
295 	void	ackFrame();
296 	void	ttyconnectFrame();
297 	void	ttyackFrame();
298 	void	pollFrame();
299 	void	identFrame();
300 	void	pingFrame();
301 	void	statFrame();
302 	void	disconnectFrame();
303 	void	abortFrame();
304 	void	ackAbortFrame();
305 	void	beaconFrame(std::string txt);
306 	void	textFrame(cTxtBlk block);
307 	void    talkFrame(std::string txt);
308 
309 	void	addToTxQue(std::string s);
310 
311 	void	sendblocks();
312 	void	transmitdata();
313 
frame()314 	std::string	frame() {return Frame;}
315 
316 	bool	isUrcall();
317 	void	parseIDENT();
318 	void	parseCONREQ();
319 	void	parseCONACK();
320 	void	parseREFUSED();
321 	void	parseDISREQ();
322 	void	parseDISACK();
323 	void	parseABORT();
324 	void	parseACKABORT();
325 	void	parseUNPROTO();
326 	void	parseSTATUS();
327 	void	parsePOLL();
328 	void	parseDATA();
329 	void	parseTALK();
330 
331 	int		parseFrame(std::string txt);
332 
333 // external functions called by arq class
334 	void	(*sendfnc)(const std::string& s);
335 	bool	(*getc1)(char &);
336 	void	(*rcvfnc)();
337 	void	(*printRX)(std::string s);
338 	void	(*printTX)(std::string s);
339 	void	(*printRX_DEBUG)(std::string s);
340 	void	(*printTX_DEBUG)(std::string s);
341 	void	(*printTALK)(std::string s);
342 	void	(*abortfnc)();
343 	void	(*disconnectfnc)();
344 	void	(*rxUrCall)(std::string s);
345 	void	(*qualityfnc)(std::string s);
346 	void	(*printSTATUS)(std::string s, double disptime);
347 
348 public:
349 	arq();
~arq()350 	~arq() {};
351 
352 	friend	void	arqloop(void *me);
353 	void	start_arq();
354 
355 	void	restart_arq();
356 
357 	std::string	checksum(std::string &s);
358 
myCall(std::string s)359 	void	myCall(std::string s) { MyCall = upcase(s);}
myCall()360 	std::string	myCall() { return MyCall;}
361 
urCall(std::string s)362 	void	urCall(std::string s) { UrCall = s;}
urCall()363 	std::string	urCall() { return UrCall;}
364 
365 	void	newsession();
366 
setSendFunc(void (* f)(const std::string & s))367 	void	setSendFunc( void (*f)(const std::string& s)) { sendfnc = f;}
setGetCFunc(bool (* f)(char &))368 	void	setGetCFunc( bool (*f)(char &)) { getc1 = f;}
setRcvFunc(void (* f)())369 	void	setRcvFunc( void (*f)()) { rcvfnc = f;}
370 
setPrintRX(void (* f)(std::string s))371 	void	setPrintRX( void (*f)(std::string s)) { printRX = f;}
setPrintTX(void (* f)(std::string s))372 	void	setPrintTX( void (*f)(std::string s)) { printTX = f;}
setPrintTALK(void (* f)(std::string s))373 	void	setPrintTALK (void (*f)(std::string s)) {printTALK = f;}
setPrintRX_DEBUG(void (* f)(std::string s))374 	void	setPrintRX_DEBUG (void (*f)(std::string s)){printRX_DEBUG = f;}
setPrintTX_DEBUG(void (* f)(std::string s))375 	void	setPrintTX_DEBUG (void (*f)(std::string s)) {printTX_DEBUG = f;}
setPrintSTATUS(void (* f)(std::string s,double disptime))376 	void	setPrintSTATUS (void (*f)(std::string s, double disptime)) { printSTATUS = f;}
377 
setMaxHeaders(int mh)378 	void	setMaxHeaders( int mh ) { maxheaders = mh; }
setExponent(int exp)379 	void	setExponent( int exp ) { exponent = exp; setBufferlength(); }
getExponent()380 	int		getExponent() { return (int) exponent;}
setWaitTime(int rtime)381 	void	setWaitTime( int rtime ) { RetryTime = rtime; baseRetryTime = rtime; }
getWaitTime()382 	int		getWaitTime() { return (int) RetryTime; }
setRetries(int rtries)383 	void	setRetries ( int rtries ) {
384 				retries = Retries = baseRetries = rtries; }
getRetries()385 	int		getRetries() { return (int) Retries; }
setTimeout(int tout)386 	void	setTimeout ( int tout ) { Timeout = tout; baseTimeout = tout; }
getTimeout()387 	int		getTimeout() { return (int) Timeout; }
getTimeLeft()388 	int		getTimeLeft() { return (int) timeout * ARQLOOPTIME / 1000; }
setTxDelay(int r2t)389 	void	setTxDelay ( int r2t ) { TxDelay = r2t; }
getTxDelay()390 	int		getTxDelay() { return (int) TxDelay; }
getRetryCount()391 	int		getRetryCount() { return (int)(Retries - retries + 1); }
392 
set_idtimer()393 	void	set_idtimer() {
394 		if (idtimer) _idtimer = (idtimer * 60 - 10) * 1000 / ARQLOOPTIME;
395 		else _idtimer = (10 * 60 - 10) * 1000 / ARQLOOPTIME;
396 	}
397 
setrxUrCall(void (* f)(std::string s))398 	void	setrxUrCall( void (*f)(std::string s)) { rxUrCall = f;}
setQualityValue(void (* f)(std::string s))399 	void	setQualityValue( void (*f)(std::string s)) { qualityfnc = f;}
setAbortedTransfer(void (* f)())400 	void	setAbortedTransfer( void (*f)()) { abortfnc = f;};
setDisconnected(void (* f)())401 	void	setDisconnected( void (*f)()) { disconnectfnc = f;};
402 
403 	void	rcvChar( char c );
404 
405 	void	connect(std::string callsign);//, int blocksize = 6, int retries = 4);
406 
407 	void	sendblocks( std::string txt );
408 
409 	void	sendBeacon (std::string txt);
410 	void	sendPlainText( std::string txt );
411 
getText()412 	std::string	getText() { return RxTextQueue;}
413 	void	sendText(std::string txt);
414 
connected()415 	bool	connected() { return (LinkState == ARQ_CONNECTED); }
416 	void	disconnect();
417 	void	abort();
418 
state()419 	int		state() { return (LinkState + Sending);}
420 
TXblocks()421 	int     TXblocks() { return totalTx;}
TXbad()422 	int     TXbad() { return nbrbadTx;}
RXblocks()423 	int     RXblocks() { return totalRx;}
RXbad()424 	int     RXbad() { return nbrbadRx;}
425 
quality()426 	double	quality() {
427 		if (totalTx == 0) return 1.0;
428 		return ( 1.0 * (totalTx - nbrbadTx) / totalTx );
429 	}
430 
percentSent()431 	float  percentSent() {
432 		if (Blocks2Send == 0) return 0.0;
433 		if ((TxBlocks.empty() && TxMissing.empty())) return 1.0;
434 		return (1.0 * (Blocks2Send - TxBlocks.size() - TxMissing.size()) / Blocks2Send);
435 	}
436 
transferComplete()437 	bool	transferComplete() {
438 		if (TxMissing.empty() == false) return false;
439 		if (TxBlocks.empty() == false) return false;
440 		return true;
441 	}
442 };
443 
444 #endif
445 
446