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