1 /**
2  * yatemodem.h
3  * This file is part of the YATE Project http://YATE.null.ro
4  *
5  * Yet Another Modem
6  *
7  * Yet Another Telephony Engine - a fully featured software PBX and IVR
8  * Copyright (C) 2004-2014 Null Team
9  *
10  * This software is distributed under multiple licenses;
11  * see the COPYING file in the main directory for licensing
12  * information for this specific distribution.
13  *
14  * This use of this software may be subject to additional restrictions.
15  * See the LEGAL file in the main directory for details.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #ifndef __YATEMODEM_H
23 #define __YATEMODEM_H
24 
25 #include <yateclass.h>
26 
27 #ifdef _WINDOWS
28 
29 #ifdef LIBYMODEM_EXPORTS
30 #define YMODEM_API __declspec(dllexport)
31 #else
32 #ifndef LIBYMODEM_STATIC
33 #define YMODEM_API __declspec(dllimport)
34 #endif
35 #endif
36 
37 #endif /* _WINDOWS */
38 
39 #ifndef YMODEM_API
40 #define YMODEM_API
41 #endif
42 
43 
44 /**
45  * Holds all Telephony Engine related classes.
46  */
47 namespace TelEngine {
48 
49 class BitAccumulator;                    // 1-byte length bit accumulator
50 class FSKModem;                          // Frequency Shift Keying modulator/demodulator
51 class UART;                              // UART receiver/transmitter
52 class UARTBuffer;                        // A byte accumulator used by an UART
53 class ETSIModem;                         // An analog signal processor as defined by ETSI
54 // Internal forward declarations
55 class BitBuffer;                         // Used to accumulate all bits to be printed to output
56 class FSKFilter;                         // The internal signal filter
57 
58 
59 /**
60  * This class encapsulates an 8 bits length buffer used to accumulate bits
61  * @short A 1-byte length bit accumulator
62  */
63 class YMODEM_API BitAccumulator
64 {
65 public:
66     /**
67      * Constructor
68      * @param dataBits The buffer size. Values interval 1..8
69      */
BitAccumulator(unsigned char dataBits)70     inline BitAccumulator(unsigned char dataBits)
71 	: m_crtByte(0), m_crtPos(0), m_dataBits(dataBits), m_oddParity(false)
72 	{}
73 
74     /**
75      * Get the buffer size
76      * @return The buffer size
77      */
dataBits()78     inline unsigned char dataBits() const
79 	{ return m_dataBits; }
80 
81     /**
82      * Set the buffer size. Reset the accumulator
83      * @param value The new buffer size. Values interval 1..8
84      */
dataBits(unsigned char value)85     inline void dataBits(unsigned char value) {
86 	    m_dataBits = value;
87 	    reset();
88 	}
89 
90     /**
91      * Reset the accumulator. Returns the old data
92      * @param oddParity Optional pointer to get the parity of old data
93      * @return The old data
94      */
95     inline unsigned char reset(bool* oddParity = 0) {
96 	    unsigned char tmp = m_crtByte;
97 	    m_crtByte = m_crtPos = 0;
98 	    if (oddParity)
99 		*oddParity = m_oddParity;
100 	    m_oddParity = false;
101 	    return tmp;
102 	}
103 
104     /**
105      * Accumulate a bit. Reset accumulator when full
106      * @param bit The bit value to accumulate
107      * @param oddParity Optional pointer to get the data parity when full
108      * @return The accumulated byte or a value greater then 255 if incomplete
109      */
110     inline unsigned int accumulate(bool bit, bool* oddParity = 0) {
111 	    if (bit) {
112 		m_crtByte |= (1 << m_crtPos);
113 		m_oddParity = !m_oddParity;
114 	    }
115 	    m_crtPos++;
116 	    if (m_crtPos != m_dataBits)
117 		return 0xffff;
118 	    return reset(oddParity);
119 	}
120 
121 private:
122     unsigned char m_crtByte;             // Current partial byte
123     unsigned char m_crtPos;              // Current free bit position
124     unsigned char m_dataBits;            // The length of a data byte (interval: 1..8)
125     bool m_oddParity;                    // The parity of the current byte value (true: odd)
126 };
127 
128 
129 /**
130  * This is a modulator/demodulator class attached to an UART. Used to demodulate bits
131  *  from frequency modulated signal and send them to an UART
132  * @short A Frequency Shift Keying modem
133  */
134 class YMODEM_API FSKModem
135 {
136 public:
137     /**
138      * Modem type enumeration
139      */
140     enum Type {
141 	ETSI = 0,                        // ETSI caller id signal: MARK:1200 SPACE:2200 BAUDRATE:1200
142 	                                 //  SAMPLERATE:8000 SAMPLES/BIT:7 STOPBITS:1 PARITY:NONE
143 	TypeCount = 1
144 	// NOTE: Don't change these values: they are used as array indexes
145     };
146 
147     /**
148      * Constructor
149      * @param params Modem parameters (including modemtype)
150      * @param uart The UART attached to this modem
151      */
152     FSKModem(const NamedList& params, UART* uart);
153 
154     /**
155      * Destructor
156      */
157     ~FSKModem();
158 
159     /**
160      * Check if this modem is terminated. Need reset if so.
161      * The modem can terminate processing on UART's request
162      * @return True if this modem is terminated
163      */
terminated()164     inline bool terminated() const
165 	{ return m_terminated; }
166 
167     /**
168      * Get the type of this modem
169      * @return The modem type
170      */
type()171     inline int type() const
172 	{ return m_type; }
173 
174     /**
175      * Reset modem to its initial state
176      */
177     void reset();
178 
179     /**
180      * Data processor. Demodulate received data. Feed the UART with received bits
181      * @param data The data to process
182      * @return False to stop feedding data (terminated)
183      */
184     bool demodulate(const DataBlock& data);
185 
186     /**
187      * Create a buffer containing the modulated representation of a message.
188      * A data pattern (depending on modem's type) will be added before the message.
189      * A mark pattern (2ms long) will be added after the message.
190      * Reset the modem before each request to modulate
191      * @param dest Destination buffer
192      * @param data Message data (each byte will be enclosed in start/stop/parity bits)
193      */
194     void modulate(DataBlock& dest, const DataBlock& data);
195 
196     /**
197      * Append a raw buffer to a data block
198      * @param dest Destination buffer
199      * @param buf Buffer to append to destination
200      * @param len the number of bytes to append starting with buf
201      */
addRaw(DataBlock & dest,void * buf,unsigned int len)202     static inline void addRaw(DataBlock& dest, void* buf, unsigned int len) {
203 	    DataBlock tmp(buf,len,false);
204 	    dest += tmp;
205 	    tmp.clear(false);
206 	}
207 
208     /**
209      * Keep the modem type names. Useful to configure the modem
210      */
211     static TokenDict s_typeName[];
212 
213 private:
214     int m_type;                          // Modem type
215     bool m_terminated;                   // Terminated flag (need reset if true)
216     FSKFilter* m_filter;                 // Internal filter used to demodulate received data
217     UART* m_uart;                        // The UART using this modem's services
218     DataBlock m_buffer;                  // Partial input buffer when used to demodulate or modulate data
219     BitBuffer* m_bits;                   // Bit buffer used when debugging
220 };
221 
222 
223 /**
224  * Accumulate data bits received from a modem
225  * @short An UART receiver/transmitter
226  */
227 class YMODEM_API UART : public DebugEnabler
228 {
229 public:
230     /**
231      * UART state enumeration
232      */
233     enum State {
234 	Idle,                            // Not started
235 	BitStart,                        // Waiting for start bit (SPACE)
236 	BitData,                         // Accumulate data bits
237 	BitParity,                       // Waiting for parity bit(s)
238 	BitStop,                         // Waiting for stop bit (MARK)
239 	UARTError,                       // Error
240     };
241 
242     /**
243      * UART error enumeration
244      */
245     enum Error {
246 	EFraming,                        // Frame error: invalid stop bit(s)
247 	EParity,                         // Parity error
248 	EChksum,                         // Message checksum error
249 	EInvalidData,                    // Invalid (inconsistent) data
250 	EUnknown,                        // Unknown error
251 	EStopped,                        // Aborted by descendants
252 	ENone
253     };
254 
255     /**
256      * Constructor
257      * @param state The initial state of this UART
258      * @param params The UART's parameters
259      * @param name The name of this debug enabler
260      */
261     UART(State state, const NamedList& params, const char* name = 0);
262 
263     /**
264      * Destructor
265      */
~UART()266     virtual ~UART()
267 	{}
268 
269     /**
270      * Get the current state of this UART
271      * @return The current state of this UART as enumeration
272      */
state()273     inline State state() const
274 	{ return m_state; }
275 
276     /**
277      * Get the current error state of this UART, if any
278      * @return The current error state of this UART as enumeration
279      */
error()280     inline Error error() const
281 	{ return m_error; }
282 
283     /**
284      * Get the type of this UART's modem
285      * @return The type of this UART's modem
286      */
modemType()287     inline int modemType() const
288 	{ return m_modem.type(); }
289 
290     /**
291      * Get the data bit accumulator used by this UART
292      * @return The data bit accumulator used by this UART
293      */
accumulator()294     inline const BitAccumulator& accumulator() const
295 	{ return m_accumulator; }
296 
297     /**
298      * Reset this UART
299      * @param newState The state to reset to
300      */
301     virtual void reset(State newState = Idle);
302 
303     /**
304      * Send data to the enclosed modem to be demodulated
305      * @param data The data to process
306      * @return False to stop processing
307      */
demodulate(const DataBlock & data)308     inline bool demodulate(const DataBlock& data)
309 	{ return m_modem.demodulate(data); }
310 
311     /**
312      * Create a buffer containing the modulated representation of a list of parameters
313      * @param dest Destination buffer
314      * @param params The list containing the values to be modulated
315      * @return False on failure (an 'error' parameter will be set in params)
316      */
modulate(DataBlock & dest,NamedList & params)317     inline bool modulate(DataBlock& dest, NamedList& params) {
318 	    DataBlock data;
319 	    if (!createMsg(params,data))
320 		return false;
321 	    m_modem.modulate(dest,data);
322 	    return true;
323 	}
324 
325     /**
326      * Create a buffer containing the modulated representation of another one
327      * @param dest Destination buffer
328      * @param src Source buffer
329      */
modulate(DataBlock & dest,const DataBlock & src)330     inline void modulate(DataBlock& dest, const DataBlock& src)
331 	{ m_modem.modulate(dest,src); }
332 
333     /**
334      * Push a bit of data into this UART. Once a data byte is accumulated, push it back to itself
335      * @param value The bit to be processed
336      * @return False to stop feeding data
337      */
338     bool recvBit(bool value);
339 
340     /**
341      * Push a data byte into this UART
342      * @param data The byte to be processed
343      * @return False to stop feeding data
344      */
recvByte(unsigned char data)345     virtual bool recvByte(unsigned char data)
346 	{ return false; }
347 
348     /**
349      * Notification from modem that the FSK start was detected
350      * @return False to stop the modem
351      */
fskStarted()352     virtual bool fskStarted()
353 	{ return true; }
354 
355     /**
356      * Keeps the names associated with UART errors
357      */
358     static TokenDict s_errors[];
359 
360 protected:
361     /**
362      * Process an accumulated byte in Idle state
363      * @param data The byte to process
364      * @return Negative to stop, positive to change state to BitStart, 0 to continue
365      */
idleRecvByte(unsigned char data)366     virtual int idleRecvByte(unsigned char data)
367 	{ return false; }
368 
369     /**
370      * Create a buffer containing the byte representation of a message to be sent
371      * @param params The list containing message parameters
372      * @param data Destination message data buffer
373      * @return False on failure
374      */
createMsg(NamedList & params,DataBlock & data)375     virtual bool createMsg(NamedList& params, DataBlock& data)
376 	{ return false; }
377 
378     /**
379      * Set the error state of this UART
380      * @param e The error
381      * @return False
382      */
383     bool error(Error e);
384 
385 private:
386     // Change this UART's state
387     void changeState(State newState);
388 
389     FSKModem m_modem;                    // The modem used by this UART
390     State m_state;                       // The state of this UART
391     Error m_error;                       // The error type if state is error
392     int m_parity;                        // Used parity: 0=none, -1=odd, 1=even
393     bool m_expectedParity;               // The expected value of the parity bit if used
394     BitAccumulator m_accumulator;        // The data bits accumulator
395 };
396 
397 
398 /**
399  * This class is used by an UART to accumulate messages with known length
400  * @short A fixed length byte accumulator used by an UART
401  */
402 class YMODEM_API UARTBuffer
403 {
404 public:
405     /**
406      * Constructor
407      * @param client The client of this buffer
408      */
UARTBuffer(UART * client)409     inline UARTBuffer(UART* client)
410 	: m_client(client)
411 	{ reset(); }
412 
413     /**
414      * Get the accumulated data
415      * @return The accumulated data
416      */
buffer()417     inline const DataBlock& buffer() const
418 	{ return m_buffer; }
419 
420     /**
421      * Get the free space length in the buffer
422      * @return The free space length
423      */
free()424     inline unsigned int free() const
425 	{ return m_free; }
426 
427     /**
428      * Reset the buffer
429      * @param len The new length of the buffer. Set to 0 to left the length unchanged
430      */
431     inline void reset(unsigned int len = 0) {
432 	    m_buffer.clear();
433 	    m_crtIdx = m_free = 0;
434 	    if (len) {
435 		m_buffer.assign(0,len);
436 		m_free = len;
437 	    }
438 	}
439 
440     /**
441      * Accumulate data
442      * @param value The value to append to the buffer
443      * @return False on buffer overflow
444      */
accumulate(unsigned char value)445     inline bool accumulate(unsigned char value) {
446 	    if (m_free) {
447 		((unsigned char*)m_buffer.data())[m_crtIdx++] = value;
448 		m_free--;
449 		return true;
450 	    }
451 	    Debug(m_client,DebugNote,"Buffer overflow");
452 	    return false;
453 	}
454 
455 private:
456     UART* m_client;                      // The client
457     unsigned int m_crtIdx;               // Current index n buffer
458     unsigned int m_free;                 // Free buffer length
459     DataBlock m_buffer;                  // The buffer
460 };
461 
462 
463 /**
464  * This class implements a modem/UART pair used to demodulate/decode analog signal as defined
465  *  in ETSI EN 300 659-1, ETSI EN 300 659-2, ETSI EN 300 659-3
466  * @short An analog signal processor as defined by ETSI
467  */
468 class YMODEM_API ETSIModem : public UART
469 {
470 public:
471     /**
472      * The state of this ETSI decoder
473      */
474     enum State {
475 	StateError,                      // Error encountered: need reset
476 	WaitFSKStart,                    // Waiting for data start pattern
477 	WaitMark,                        // Waiting for mark pattern
478 	WaitMsg,                         // Wait a message
479 	WaitMsgLen,                      // Received message: wait length
480 	WaitParam,                       // Wait a parameter
481 	WaitParamLen,                    // Received parameter: wait length
482 	WaitData,                        // Received parameter length: wait data
483 	WaitChksum,                      // Wait checksum
484     };
485 
486     /**
487      * Message type defined in ETSI EN 659-3 5.2
488      */
489     enum MsgType {
490 	MsgCallSetup = 0x80,             // Call setup
491 	MsgMWI       = 0x82,             // Message waiting indicator
492 	MsgCharge    = 0x86,             // Advise of charge
493 	MsgSMS       = 0x89,             // Short message service
494     };
495 
496     /**
497      * Message parameters defined in ETSI EN 659-3 5.3
498      */
499     enum MsgParam {
500 	DateTime         = 0x01,         // 8		Date and Time
501 	CallerId         = 0x02,         // max. 20	Calling Line Identity
502 	CalledId         = 0x03,         // max. 20	Called Line Identity
503 	CallerIdReason   = 0x04,         // 1		Reason for Absence of Calling Line Identity
504 	CallerName       = 0x07,         // max. 50	Calling Party Name
505 	CallerNameReason = 0x08,         // 1		Reason for absence of Calling Party Name
506 	VisualIndicator  = 0x0B,         // 1		Visual Indicator
507 	MessageId        = 0x0D,         // 3		Message Identification
508 	LastMsgCLI       = 0x0E,         // max. 20	Last Message CLI
509 	CompDateTime     = 0x0F,         // 8 or 10	Complementary Date and Time
510 	CompCallerId     = 0x10,         // max. 20	Complementary Calling Line Identity
511 	CallType         = 0x11,         // 1		Call type
512 	FirstCalledId    = 0x12,         // max. 20	First Called Line Identity
513 	MWICount         = 0x13,         // 1		Number of Messages
514 	FwdCallType      = 0x15,         // 1		Type of Forwarded call
515 	CallerType       = 0x16,         // 1		Type of Calling user
516 	RedirNumber      = 0x1A,         // max. 20	Redirecting Number
517 	Charge           = 0x20,         // 14		Charge
518 	AdditionalCharge = 0x21,         // 14		Additional Charge
519 	Duration         = 0x23,         // 6		Duration of the Call
520 	NetworkID        = 0x30,         // max. 20	Network Provider Identity
521 	CarrierId        = 0x31,         // max. 20	Carrier Identity
522 	SelectFunction   = 0x40,         // 2-21        Selection of Terminal Function
523 	Display          = 0x50,         // max. 253	Display Information
524 	ServiceInfo      = 0x55,         // 1		Service Information
525 	Extension        = 0xE0,         // 10		Extension for network operator use
526 	Unknown
527     };
528 
529     /**
530      * Constructor
531      * @param params Decoder parameters
532      * @param name The name of this debug enabler
533      */
534     ETSIModem(const NamedList& params, const char* name = 0);
535 
536     /**
537      * Destructor
538      */
539     virtual ~ETSIModem();
540 
541     /**
542      * Reset this decoder (modem and UART)
543      */
544     virtual void reset();
545 
546     /**
547      * Push a data byte into this decoder. Reset this UART and call decode after validated a received message
548      * @param data The byte to be processed
549      * @return False to stop feeding data
550      */
551     virtual bool recvByte(unsigned char data);
552 
553     /**
554      * Keeps the text associated with message type enumeration
555      */
556     static TokenDict s_msg[];
557 
558     /**
559      * Keeps the text associated with parameter type enumeration
560      */
561     static TokenDict s_msgParams[];
562 
563 protected:
564     /**
565      * Process an accumulated byte in Idle state
566      * @param data The byte to process
567      * @return Negative to stop, positive to change state to BitStart, 0 to continue
568      */
569     virtual int idleRecvByte(unsigned char data);
570 
571     /**
572      * Process a list of received message parameters
573      * @param msg The message type as enumeration
574      * @param params Message parameters
575      * @return False to stop processing data
576      */
recvParams(MsgType msg,const NamedList & params)577     virtual bool recvParams(MsgType msg, const NamedList& params)
578 	{ return false; }
579 
580     /**
581      * Process (decode) a valid received buffer. Call recvParams() after decoding the message
582      * @param msg The message type as enumeration
583      * @param buffer The accumulated data bytes
584      * @return False to stop processing data
585      */
586     virtual bool decode(MsgType msg, const DataBlock& buffer);
587 
588     /**
589      * Create a buffer containing the byte representation of a message to be sent
590      * @param params The list containing message parameters.
591      *  The name of the list must be a valid (known) message
592      * @param data Destination message data buffer
593      * @return False on failure (an 'error' parameter will be set in params)
594      */
595     virtual bool createMsg(NamedList& params, DataBlock& data);
596 
597 private:
598     // Change decoder's state
599     void changeState(State newState);
600 
601     UARTBuffer m_buffer;                 // The buffer used to accumulate messages
602     State m_state;                       // Decoder state
603     unsigned char m_waitSeizureCount;    // Expected number of channel seizure bytes in a row
604     unsigned char m_crtSeizureCount;     // Current number of channel seizure bytes in a row
605     unsigned char m_crtMsg;              // Current message id
606     unsigned char m_crtParamLen;         // Current receiving parameter length
607     unsigned int m_chksum;               // Current calculated checksum
608 };
609 
610 }
611 
612 #endif /* __YATEMODEM_H */
613 
614 /* vi: set ts=8 sw=4 sts=4 noet: */
615