1 /** 2 * yateradio.h 3 * Radio library 4 * This file is part of the YATE Project http://YATE.null.ro 5 * 6 * Yet Another Telephony Engine - a fully featured software PBX and IVR 7 * Copyright (C) 2011-2014 Null Team 8 * Copyright (C) 2015 LEGBA Inc 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 __YATERADIO_H 23 #define __YATERADIO_H 24 25 #include <yateclass.h> 26 #include <yatexml.h> 27 28 #ifdef _WINDOWS 29 30 #ifdef LIBYRADIO_EXPORTS 31 #define YRADIO_API __declspec(dllexport) 32 #else 33 #ifndef LIBYRADIO_STATIC 34 #define YRADIO_API __declspec(dllimport) 35 #endif 36 #endif 37 38 #endif /* _WINDOWS */ 39 40 #ifndef YRADIO_API 41 #define YRADIO_API 42 #endif 43 44 45 namespace TelEngine { 46 47 class GSML3Codec; // GSM Layer codec 48 class RadioCapability; // Radio device capabilities 49 class RadioInterface; // Generic radio interface 50 51 class YRADIO_API GSML3Codec 52 { 53 YNOCOPY(GSML3Codec); 54 public: 55 /** 56 * Codec flags 57 */ 58 enum Flags { 59 XmlDumpMsg = 0x01, 60 XmlDumpIEs = 0x02, 61 MSCoder = 0x04, 62 }; 63 64 /** 65 * Codec return status 66 */ 67 enum Status { 68 NoError = 0, 69 MsgTooShort, 70 UnknownProto, 71 ParserErr, 72 MissingParam, 73 IncorrectOptionalIE, 74 IncorrectMandatoryIE, 75 MissingMandatoryIE, 76 UnknownMsgType, 77 }; 78 79 /** 80 * Protocol discriminator according to ETSI TS 124 007 V11.0.0, section 11.2.3.1.1 81 */ 82 enum Protocol { 83 GCC = 0x00, // Group Call Control 84 BCC = 0x01, // Broadcast Call Control 85 EPS_SM = 0x02, // EPS Session Management 86 CC = 0x03, // Call Control; Call Related SS messages 87 GTTP = 0x04, // GPRS Transparent Transport Protocol (GTTP) 88 MM = 0x05, // Mobility Management 89 RRM = 0x06, // Radio Resources Management 90 EPS_MM = 0x07, // EPS Mobility Management 91 GPRS_MM = 0x08, // GPRS Mobility Management 92 SMS = 0x09, // SMS 93 GPRS_SM = 0x0a, // GPRS Session Management 94 SS = 0x0b, // Non Call Related SS messages 95 LCS = 0x0c, // Location services 96 Extension = 0x0e, // reserved for extension of the PD to one octet length 97 Test = 0x0f, // used by tests procedures described in 3GPP TS 44.014, 3GPP TS 34.109 and 3GPP TS 36.509 98 Unknown = 0xff, 99 }; 100 101 /** 102 * IE types 103 */ 104 enum Type { 105 NoType = 0, 106 T, 107 V, 108 TV, 109 LV, 110 TLV, 111 LVE, 112 TLVE, 113 }; 114 115 /** 116 * Type of XML data to generate 117 */ 118 enum XmlType { 119 Skip, 120 XmlElem, 121 XmlRoot, 122 }; 123 124 /** 125 * EPS Security Headers 126 */ 127 enum EPSSecurityHeader { 128 PlainNAS = 0x00, 129 IntegrityProtect = 0x01, 130 IntegrityProtectCiphered = 0x02, 131 IntegrityProtectNewEPSCtxt = 0x03, 132 IntegrityProtectCipheredNewEPSCtxt = 0x04, 133 ServiceRequestHeader = 0xa0, 134 }; 135 136 /** 137 * Constructor 138 */ 139 GSML3Codec(DebugEnabler* dbg = 0); 140 141 /** 142 * Decode layer 3 message payload 143 * @param in Input buffer containing the data to be decoded 144 * @param len Length of input buffer 145 * @param out XmlElement into which the decoded data is returned 146 * @param params Encoder parameters 147 * @return Parsing result: 0 (NoError) if succeeded, error status otherwise 148 */ 149 unsigned int decode(const uint8_t* in, unsigned int len, XmlElement*& out, const NamedList& params = NamedList::empty()); 150 151 /** 152 * Encode a layer 3 message 153 * @param in Layer 3 message in XML form 154 * @param out Output buffer into which to put encoded data 155 * @param params Encoder parameters 156 * @return Parsing result: 0 (NoError) if succeeded, error status otherwise 157 */ 158 unsigned int encode(const XmlElement* in, DataBlock& out, const NamedList& params = NamedList::empty()); 159 160 /** 161 * Decode layer 3 message from an existing XML 162 * @param xml XML which contains layer 3 messages to decode and into which the decoded XML will be put 163 * @param params Decoder parameters 164 * @return Parsing result: 0 (NoError) if succeeded, error status otherwise 165 */ 166 unsigned int decode(XmlElement* xml, const NamedList& params = NamedList::empty()); 167 168 /** 169 * Encode a layer 3 message from an existing XML 170 * @param xml XML which contains a layer 3 message in XML form. The message will be replaced with its encoded buffer 171 * @param params Encoder parameters 172 * @return Parsing result: 0 (NoError) if succeeded, error status otherwise 173 */ 174 unsigned int encode(XmlElement* xml, const NamedList& params = NamedList::empty()); 175 176 /** 177 * Set data used in debug 178 * @param enabler The DebugEnabler to use (0 to to use the engine) 179 * @param ptr Pointer to print, 0 to use the codec pointer 180 */ 181 void setCodecDebug(DebugEnabler* enabler = 0, void* ptr = 0); 182 183 /** 184 * Retrieve codec flags 185 * @return Codec flags 186 */ flags()187 inline uint8_t flags() const 188 { return m_flags; } 189 190 /** 191 * Set codec flags 192 * @param flgs Flags to set 193 * @param reset Reset flags before setting these ones 194 */ 195 inline void setFlags(uint8_t flgs, bool reset = false) 196 { 197 if (reset) 198 resetFlags(); 199 m_flags |= flgs; 200 } 201 202 /** 203 * Reset codec flags 204 * @param flgs Flags to reset. If 0, all flags are reset 205 */ 206 inline void resetFlags(uint8_t flgs = 0) 207 { 208 if (flgs) 209 m_flags &= ~flgs; 210 else 211 m_flags = 0; 212 } 213 214 /** 215 * Activate printing of debug messages 216 * @param on True to activate, false to disable 217 */ 218 inline void setPrintDbg(bool on = false) 219 { m_printDbg = on; } 220 221 /** 222 * Get printing of debug messages flag 223 * @return True if debugging is activated, false otherwise 224 */ printDbg()225 inline bool printDbg() const 226 { return m_printDbg; } 227 228 /** 229 * Get DebugEnabler used by this codec 230 * @return DebugEnabler used by the codec 231 */ dbg()232 inline DebugEnabler* dbg() const 233 { return m_dbg; } 234 235 /** 236 * Retrieve the codec pointer used for debug messages 237 * @return Codec pointer used for debug messages 238 */ ptr()239 inline void* ptr() const 240 { return m_ptr; } 241 242 /** 243 * Decode GSM 7bit buffer 244 * @param buf Input buffer 245 * @param len Input buffer length 246 * @param text Destination text 247 * @param heptets Maximum number of heptets in buffer 248 */ 249 static void decodeGSM7Bit(unsigned char* buf, unsigned int len, String& text, 250 unsigned int heptets = (unsigned int)-1); 251 252 /** 253 * Encode GSM 7bit buffer 254 * @param text Input text 255 * @param buf Destination buffer 256 * @return True if all characters were encoded correctly 257 */ 258 static bool encodeGSM7Bit(const String& text, DataBlock& buf); 259 260 /** 261 * IE types dictionary 262 */ 263 static const TokenDict s_typeDict[]; 264 265 /** 266 * L3 Protocols dictionary 267 */ 268 static const TokenDict s_protoDict[]; 269 270 /** 271 * EPS Security Headers dictionary 272 */ 273 static const TokenDict s_securityHeaders[]; 274 275 /** 276 * Errors dictionary 277 */ 278 static const TokenDict s_errorsDict[]; 279 280 /** 281 * Mobility Management reject causes dictionary 282 */ 283 static const TokenDict s_mmRejectCause[]; 284 285 /** 286 * GPRS Mobility Management reject causes dictionary 287 */ 288 static const TokenDict s_gmmRejectCause[]; 289 290 private: 291 292 unsigned int decodeXml(XmlElement* xml, const NamedList& params, const String& pduTag); 293 unsigned int encodeXml(XmlElement* xml, const NamedList& params, const String& pduTag); 294 void printDbg(int dbgLevel, const uint8_t* in, unsigned int len, XmlElement* xml, bool encode = false); 295 296 uint8_t m_flags; // Codec flags 297 // data used for debugging messages 298 DebugEnabler* m_dbg; 299 void* m_ptr; 300 // activate debug 301 bool m_printDbg; 302 }; 303 304 305 /** 306 * @short Radio device capabilities 307 * Radio capability object describes the parameter ranges of the radio handware. 308 */ 309 class YRADIO_API RadioCapability 310 { 311 public: 312 /** 313 * Constructor 314 */ 315 RadioCapability(); 316 317 unsigned maxPorts; // Available number of ports 318 unsigned currPorts; // Number of used (available) ports 319 uint64_t maxTuneFreq; // Maximum allowed tuning frequency (in Hz) 320 uint64_t minTuneFreq; // Minimum allowed tuning frequency (in Hz) 321 unsigned maxSampleRate; // Maximum allowed sampling rate (in Hz) 322 unsigned minSampleRate; // Minimum allowed sampling rate (in Hz) 323 unsigned maxFilterBandwidth; // Maximum allowed anti-alias filter bandwidth (in Hz) 324 unsigned minFilterBandwidth; // Minimum allowed anti-alias filter bandwidth (in Hz) 325 unsigned rxLatency; // Estimated radio latency (in samples) 326 unsigned txLatency; // Estimated transmit latency (in samples) 327 }; 328 329 330 /** 331 * Keeps a buffer pointer with offset and valid samples 332 * @short A buffer description 333 */ 334 class RadioBufDesc 335 { 336 public: 337 /** 338 * Constructor 339 */ RadioBufDesc()340 inline RadioBufDesc() 341 : samples(0), offs(0), valid(0) 342 {} 343 344 /** 345 * Reset the buffer 346 * @param value Offset and valid samples value 347 */ 348 inline void reset(unsigned int value = 0) 349 { offs = valid = value; } 350 351 /** 352 * Reset the buffer 353 * @param offset New offset 354 * @param validS New valid samples value 355 */ reset(unsigned int offset,unsigned int validS)356 inline void reset(unsigned int offset, unsigned int validS) { 357 offs = offset; 358 valid = validS; 359 } 360 361 /** 362 * Check if the buffer is valid 363 * @param minSamples Required minimum number of valid samples 364 * @return True if valid, false otherwise 365 */ validSamples(unsigned int minSamples)366 inline bool validSamples(unsigned int minSamples) const 367 { return !minSamples || minSamples >= offs || minSamples >= valid; } 368 369 float* samples; // Current read buffer 370 unsigned int offs; // Current buffer offset (in sample periods) 371 unsigned int valid; // The number of valid samples in buffer 372 }; 373 374 375 /** 376 * Keeps buffers used by RadioInterface::read() 377 * @short RadioInterface read buffers 378 */ 379 class RadioReadBufs : public GenObject 380 { 381 public: 382 /** 383 * Constructor 384 * @param len Single buffer length (in sample periods) 385 * @param validThres Optional threshold for valid samples. Used when read timestamp 386 * data is in the future and a portion of the buffer need to be reset. 387 * If valid samples are below threshold data won't be set or copied 388 */ 389 inline RadioReadBufs(unsigned int len = 0, unsigned int validThres = 0) m_bufSamples(len)390 : m_bufSamples(len), m_validMin(validThres) 391 {} 392 393 /** 394 * Reset buffers 395 * @param len Single buffer length (in sample periods) 396 * @param validThres Optional threshold for valid samples 397 */ reset(unsigned int len,unsigned int validThres)398 inline void reset(unsigned int len, unsigned int validThres) { 399 m_bufSamples = len; 400 m_validMin = validThres; 401 crt.reset(); 402 aux.reset(); 403 extra.reset(); 404 } 405 406 /** 407 * Retrieve the length of a single buffer 408 * @return Buffer length (in sample periods) 409 */ bufSamples()410 inline unsigned int bufSamples() const 411 { return m_bufSamples; } 412 413 /** 414 * Check if a given buffer is full (offset is at least buffer length) 415 * @param buf Buffer to check 416 * @return True if the given buffer is full, false otherwise 417 */ full(RadioBufDesc & buf)418 inline bool full(RadioBufDesc& buf) const 419 { return buf.offs >= m_bufSamples; } 420 421 /** 422 * Check if a given is valid (have enough valid samples) 423 * @param buf Buffer to check 424 * @return True if the given buffer is valid, false otherwise 425 */ valid(RadioBufDesc & buf)426 inline bool valid(RadioBufDesc& buf) const 427 { return buf.validSamples(m_validMin); } 428 429 /** 430 * Dump data for debug purposes 431 * @param buf Destination buffer 432 * @return Destination buffer reference 433 */ 434 String& dump(String& buf); 435 436 RadioBufDesc crt; 437 RadioBufDesc aux; 438 RadioBufDesc extra; 439 440 protected: 441 unsigned int m_bufSamples; // Buffers length in sample periods 442 unsigned int m_validMin; // Valid samples threshold 443 }; 444 445 446 /** 447 * @short Generic radio interface 448 * 449 * @note Some parameters are quantized by the radio hardware. If the caller requests a parameter 450 * value that cannot be matched exactly, the setting method will set the parameter to the 451 * best avaiable match and return "NotExact". For such parameters, there is a corresponding 452 * readback method to get the actual value used. 453 * 454 * @note If a method does not include a radio port number, then that method applies to all connected ports. 455 * 456 * @note The interface may control multiple radios, with each one appearing as a port. However, in this case, 457 * - all radios are to be synched on the sample clock 458 * - all radios are to be of the same hardware type 459 * 460 * @note If the performance of the radio hardware changes, the API indicates this with the RFHardwareChange 461 * flag. If this flag appears in a result code, the application should: 462 * - read a new RadioCapabilties object 463 * - revisit all of the application-level parameter settings on the radio 464 * - check the status() method on each port to identify single-port errors 465 */ 466 class YRADIO_API RadioInterface : public RefObject, public DebugEnabler 467 { 468 YCLASS(RadioInterface,RefObject); 469 public: 470 /** Error code bit positions in the error code mask. */ 471 enum ErrorCode { 472 NoError = 0, 473 Failure = (1 << 1), // Unknown error 474 HardwareIOError = (1 << 2), // Communication error with HW 475 NotInitialized = (1 << 3), // Interface not initialized 476 NotSupported = (1 << 4), // Feature not supported 477 NotCalibrated = (1 << 5), // The radio is not calibrated 478 TooEarly = (1 << 6), // Timestamp is in the past 479 TooLate = (1 << 7), // Timestamp is in the future 480 OutOfRange = (1 << 8), // A requested parameter setting is out of range 481 NotExact = (1 << 9), // The affected value is not an exact match to the requested one 482 DataLost = (1 << 10), // Received data lost due to slow reads 483 Saturation = (1 << 11), // Data contain values outside of +/-1+/-j 484 RFHardwareFail = (1 << 12), // Failure in RF hardware 485 RFHardwareChange = (1 << 13), // Change in RF hardware, not outright failure 486 EnvironmentalFault = (1 << 14), // Environmental spec exceeded for radio HW 487 InvalidPort = (1 << 15), // Invalid port number 488 Pending = (1 << 16), // Operation is pending 489 Cancelled = (1 << 17), // Operation cancelled 490 Timeout = (1 << 18), // Operation timeout 491 HardwareNotAvailable = (1 << 19),// Device not found 492 InsufficientSpeed = (1 << 20), // Device has insufficient speed to fulfill required transfer rate 493 // Masks 494 // Errors indicating automatic application restart should not be performed 495 // These may indicate misconfig or hardware failures requiring system restart 496 NoAutoRestartMask = HardwareNotAvailable | InsufficientSpeed, 497 // Errors requiring radio or port shutdown 498 FatalErrorMask = HardwareIOError | RFHardwareFail | EnvironmentalFault | Failure | 499 NoAutoRestartMask, 500 // Errors that can be cleared 501 ClearErrorMask = TooEarly | TooLate | NotExact | DataLost | Saturation | 502 InvalidPort | Timeout, 503 // Errors that are specific to a single call 504 LocalErrorMask = NotInitialized | NotCalibrated | TooEarly | TooLate | OutOfRange | 505 NotExact | DataLost | Saturation | RFHardwareChange | InvalidPort, 506 }; 507 508 /** 509 * Operations 510 * Used to handle pending state 511 */ 512 enum Operation { 513 PendingInitialize = 0, // initialize() is pending 514 PendingCount, 515 }; 516 517 /** 518 * Poll for a pending operation 519 * @param oper Operation to check 520 * @param waitMs Optional time (in milliseconds) to wait for operation completion 521 * @return Error code (0 on success) 522 */ 523 unsigned int pollPending(unsigned int oper, unsigned int waitMs = 0); 524 525 /** 526 * Retrieve the radio device path 527 * @param devicePath Destination buffer 528 * @return Error code (0 on success) 529 */ getInterface(String & devicePath)530 virtual unsigned int getInterface(String& devicePath) const 531 { return NotSupported; } 532 533 /** 534 * Retrieve radio capabilities 535 * @return RadioCapability pointer, 0 if unknown or not implemented 536 */ capabilities()537 virtual const RadioCapability* capabilities() const 538 { return m_radioCaps; } 539 540 /** 541 * Initialize the radio interface. 542 * Any attempt to transmit or receive prior to this operation will return NotInitialized. 543 * @param params Optional parameters list 544 * @return Error code (0 on success) 545 */ 546 virtual unsigned int initialize(const NamedList& params = NamedList::empty()) = 0; 547 548 /** 549 * Set radio loopback 550 * @param name Loopback name (NULL for none) 551 * @return Error code (0 on success) 552 */ 553 virtual unsigned int setLoopback(const char* name = 0) 554 { return NotSupported; } 555 556 /** 557 * Set multiple interface parameters. 558 * Each command must start with 'cmd:' to allow the code to detect unhandled commands. 559 * Command sub-params should not start with the prefix 560 * @param params Parameters list 561 * @param shareFate True to indicate all parameters share the fate 562 * (return on first error, except for Pending), false to process all 563 * @return Error code (0 on success). Failed command(s) will be set in the list 564 * with cmd_name.code=error_code 565 */ 566 virtual unsigned int setParams(NamedList& params, bool shareFate = true) = 0; 567 568 /** 569 * Update (set/reset) interface data dump 570 * @param dir Direction to update. 0: both, negative: RX only, positive: TX only 571 * @param level Dump level to update. 0: both, negative: interface level (data 572 * sent/received by the upper layer), positive: device level (data sent to or 573 * read from radio device) 574 * @param params Optional parameters 575 * @return Error code (0 on success) 576 */ 577 virtual unsigned int setDataDump(int dir = 0, int level = 0, 578 const NamedList* params = 0) = 0; 579 580 /** 581 * Run internal calibration procedures and/or load calibration parmameters 582 * @return Error code (0 on success) 583 */ calibrate()584 virtual unsigned int calibrate() 585 { return NotSupported; } 586 587 /** 588 * Set the number of ports to be used 589 * @param count The number of ports to be used 590 * @return Error code (0 on success) 591 */ 592 virtual unsigned int setPorts(unsigned count) = 0; 593 594 /** 595 * Return any persistent error codes. 596 * ("Persistent" means a condition of the radio interface itself, 597 * as opposed to a status code related to a specific method call) 598 * @param port Port number to check, or -1 for all ports OR'd together 599 * @return Error(s) mask 600 */ 601 virtual unsigned int status(int port = -1) const = 0; 602 603 /** 604 * Clear all error codes that can be cleared. 605 * Note the not all codes are clearable, like HW failures for example. 606 */ clearErrors()607 virtual void clearErrors() 608 { m_lastErr &= ~ClearErrorMask; } 609 610 /** 611 * Send a frame of complex samples at a given time, interleaved IQ format. 612 * If there are gaps in the sample stream, the RadioInterface must zero-fill. 613 * All ports are sent together in interleaved format; example: 614 * I0 Q0 I1 Q1 I2 Q2 I0 Q0 I1 Q1 I2 Q2, etc for a 3-port system 615 * Block until the send is complete. 616 * Return TooEarly if the blocking time would be too long. 617 * Return TooLate if any of the block is in the past. 618 * @param when Time to schedule the transmission 619 * @param samples Data to send (array of 2 * size * ports floats, interleaved IQ) 620 * @param size The number of sample periods in the samples array 621 * @param powerScale Optional pointer to power scale value 622 * @return Error code (0 on success) 623 */ 624 virtual unsigned int send(uint64_t when, float* samples, unsigned size, 625 float* powerScale = 0) = 0; 626 627 /** 628 * Receive the next available samples and associated timestamp. 629 * All ports are received together in interleaved format. 630 * e.g: I0 Q0 I1 Q1 I2 Q2 I0 Q0 I1 Q1 I2 Q2, etc for a 3-port system. 631 * The method will wait for proper timestamp (to be at least requested timestamp). 632 * The caller must increase the timestamp after succesfull read. 633 * The method may return less then requested size. 634 * @param when Input: current timestamp. Output: read data timestamp 635 * @param samples Destination buffer (array of 2 * size * ports floats, interleaved IQ) 636 * @param size Input: requested number of samples. Output: actual number of read samples 637 * @return Error code (0 on success) 638 */ 639 virtual unsigned int recv(uint64_t& when, float* samples, unsigned& size) = 0; 640 641 /** 642 * Receive the next available samples and associated timestamp. 643 * Compensate timestamp difference. 644 * Copy any valid data in the future to auxiliary buffers. 645 * Adjust the timestamp (no need for the caller to do it). 646 * Handles buffer rotation also. 647 * All sample counters (length/offset) are expected in sample periods. 648 * @param when Input: current timestamp. Output: next read data timestamp 649 * @param bufs Buffers to use 650 * @param skippedBufs The number of skipped full buffers 651 * @return Error code (0 on success) 652 */ 653 virtual unsigned int read(uint64_t& when, RadioReadBufs& bufs, 654 unsigned int& skippedBufs); 655 656 /** 657 * Get the time of the data currently being received from the radio 658 * @param when Destination buffer for requested radio time 659 * @return Error code (0 on success) 660 */ 661 virtual unsigned int getRxTime(uint64_t& when) const = 0; 662 663 /** 664 * Get the time of the the data currently being sent to the radio 665 * @param when Destination buffer for requested radio time 666 * @return Error code (0 on success) 667 */ 668 virtual unsigned int getTxTime(uint64_t& when) const = 0; 669 670 /** 671 * Set the frequency offset 672 * @param offs Frequency offset to set 673 * @param newVal Optional pointer to value set by interface (requested value may 674 * be adjusted to fit specific device value) 675 * @return Error code (0 on success) 676 */ 677 virtual unsigned int setFreqOffset(float offs, float* newVal = 0) = 0; 678 679 /** 680 * Set the sample rate 681 * @param hz Sample rate value in Hertz 682 * @return Error code (0 on success) 683 */ 684 virtual unsigned int setSampleRate(uint64_t hz) = 0; 685 686 /** 687 * Get the actual sample rate 688 * @param hz Sample rate value in Hertz 689 * @return Error code (0 on success) 690 */ 691 virtual unsigned int getSampleRate(uint64_t& hz) const = 0; 692 693 /** 694 * Set the anti-aliasing filter BW 695 * @param hz Anti-aliasing filter value in Hertz 696 * @return Error code (0 on success) 697 */ 698 virtual unsigned int setFilter(uint64_t hz) = 0; 699 700 /** 701 * Get the actual anti-aliasing filter BW 702 * @param hz Anti-aliasing filter value in Hertz 703 * @return Error code (0 on success) 704 */ 705 virtual unsigned int getFilterWidth(uint64_t& hz) const = 0; 706 707 /** 708 * Set the transmit frequency in Hz 709 * @param hz Transmit frequency value 710 * @return Error code (0 on success) 711 */ 712 virtual unsigned int setTxFreq(uint64_t hz) = 0; 713 714 /** 715 * Readback actual transmit frequency 716 * @param hz Transmit frequency value 717 * @return Error code (0 on success) 718 */ 719 virtual unsigned int getTxFreq(uint64_t& hz) const = 0; 720 721 /** 722 * Set the output power in dBm. 723 * This is power per active port, compensating for internal gain differences. 724 * @param dBm The output power to set 725 * @return Error code (0 on success) 726 */ 727 virtual unsigned int setTxPower(unsigned dBm) = 0; 728 729 /** 730 * Set the receive frequency in Hz 731 * @param hz Receive frequency value 732 * @return Error code (0 on success) 733 */ 734 virtual unsigned int setRxFreq(uint64_t hz) = 0; 735 736 /** 737 * Readback actual receive frequency 738 * @param hz Receive frequency value 739 * @return Error code (0 on success) 740 */ 741 virtual unsigned int getRxFreq(uint64_t& hz) const = 0; 742 743 /** 744 * Set the transmit pre-mixer gain in dB wrt max 745 * @return Error code (0 on success) 746 */ setTxGain1(int val,unsigned port)747 virtual unsigned int setTxGain1(int val, unsigned port) 748 { return NotSupported; } 749 750 /** 751 * Set the transmit post-mixer gain in dB wrt max 752 * @return Error code (0 on success) 753 */ setTxGain2(int val,unsigned port)754 virtual unsigned int setTxGain2(int val, unsigned port) 755 { return NotSupported; } 756 757 /** 758 * Set the receive pre-mixer gain in dB wrt max 759 * @return Error code (0 on success) 760 */ setRxGain1(int val,unsigned port)761 virtual unsigned int setRxGain1(int val, unsigned port) 762 { return NotSupported; } 763 764 /** 765 * Set the receive post-mixer gain in dB wrt max 766 * @return Error code (0 on success) 767 */ setRxGain2(int val,unsigned port)768 virtual unsigned int setRxGain2(int val, unsigned port) 769 { return NotSupported; } 770 771 /** 772 * Automatic tx/rx gain setting 773 * Set post mixer value. Return a value to be used by upper layer 774 * @param tx Direction 775 * @param val Value to set 776 * @param port Port to use 777 * @param newVal Optional pointer to value to use for calculation by the upper layer 778 * @return Error code (0 on success) 779 */ 780 virtual unsigned int setGain(bool tx, int val, unsigned int port, 781 int* newVal = 0) const 782 { return NotSupported; } 783 784 /** 785 * Retrieve the interface name 786 * @return Interface name 787 */ 788 virtual const String& toString() const; 789 790 /** 791 * Complete device info parameters 792 * @param p Destination list 793 * @param full Put full device info 794 * @param retData True to set out pointer in destination, false to add name only 795 */ 796 virtual void completeDevInfo(NamedList& p, bool full = false, bool retData = false); 797 798 /** 799 * Fill (set) error related parameters 800 * @param p Destination list 801 * @param code Error code 802 * @param str Optional error string (not error name) 803 */ 804 virtual void setError(NamedList& p, unsigned int code, const char* str = 0); 805 806 /** 807 * Retrieve the error string associated with a specific code 808 * @param code Error code 809 * @param defVal Optional default value to retrieve if not found 810 * @return Valid TokenDict pointer 811 */ 812 static inline const char* errorName(int code, const char* defVal = 0) 813 { return lookup(code,errorNameDict(),defVal); } 814 815 /** 816 * Retrieve the error name dictionary 817 * @return Valid TokenDict pointer 818 */ 819 static const TokenDict* errorNameDict(); 820 821 protected: 822 /** 823 * Constructor 824 * @param name Interface name 825 */ 826 RadioInterface(const char* name); 827 828 /** 829 * Set pending state 830 * @param oper Operation to set 831 * @param code Status code 832 */ 833 inline void setPending(unsigned int oper, unsigned int code = Pending) { 834 Lock lck(m_mutex); 835 if (oper < PendingCount) 836 m_pendingCode[oper] = code; 837 } 838 839 unsigned int m_lastErr; // Last error that appeared during functioning 840 unsigned int m_totalErr; // All the errors that appeared 841 RadioCapability* m_radioCaps; // Radio capabilities 842 843 private: 844 String m_name; 845 Mutex m_mutex; 846 unsigned int m_pendingCode[PendingCount]; 847 }; 848 849 850 /** 851 * @short Radio data file header 852 * This class describes records in radio data files 853 */ 854 class YRADIO_API RadioDataDesc 855 { 856 public: 857 /** 858 * Samples data type 859 */ 860 enum ElementType { 861 Float = 0, 862 Int16 = 1, 863 }; 864 865 /** 866 * Timestamp type 867 */ 868 enum TsType { 869 TsApp = 0, // Application level timestamp 870 TsBoard = 1, // Board (device) level timestamp 871 }; 872 873 /** 874 * Constructor 875 * @param eType Element type 876 * @param tsType Racords timestamp type 877 * @param sLen Sample length in elements 878 * @param ports Number of device ports 879 */ 880 inline RadioDataDesc(uint8_t eType = Float, uint8_t tsType = TsApp, 881 uint8_t sLen = 2, uint8_t ports = 1) m_elementType(eType)882 : m_elementType(eType), m_sampleLen(sLen), m_ports(ports ? ports : 1), 883 m_tsType(tsType), 884 #ifdef LITTLE_ENDIAN 885 m_littleEndian(true) 886 #else 887 m_littleEndian(false) 888 #endif 889 { 890 m_signature[0] = 'Y'; 891 m_signature[1] = 'R'; 892 m_signature[2] = 0; 893 } 894 895 uint8_t m_signature[3]; // File signature 896 uint8_t m_elementType; // Element data type 897 uint8_t m_sampleLen; // Sample length in elements 898 uint8_t m_ports; // The number of ports 899 uint8_t m_tsType; // Records timestamp type 900 bool m_littleEndian; // Endiannes 901 }; 902 903 904 /** 905 * @short Radio data file helper 906 * This class implements utilities used to read or write radio data to/from file 907 * The String contains object name used for debug 908 */ 909 class YRADIO_API RadioDataFile : public String 910 { 911 public: 912 /** 913 * Constructor 914 * @param name Name used for debug 915 * @param dropOnError Terminate on file/data error 916 */ 917 RadioDataFile(const char* name, bool dropOnError = true); 918 919 /** 920 * Destructor 921 */ 922 virtual ~RadioDataFile(); 923 924 /** 925 * Retrieve data description 926 * @return Data description object 927 */ desc()928 inline const RadioDataDesc& desc() const 929 { return m_header; } 930 931 /** 932 * Check if enabled 933 * @return True if enabled, false otherwise 934 */ valid()935 inline bool valid() const 936 { return m_file.valid(); } 937 938 /** 939 * Check if machine endiannes is the same as file endiannes 940 * @return True if they are the same 941 */ sameEndian()942 inline bool sameEndian() const 943 { return m_littleEndian == m_header.m_littleEndian; } 944 945 /** 946 * Open a file for read/write. Terminate current data dump if any. 947 * Write or read the file header 948 * @param fileName File to open 949 * @param data Data description. Pass a NULL pointer for read or valid data for write 950 * @param dbg Optional DebugEnabler pointer (show debug on failure) 951 * @param error Optional destination for file operation error code 952 * @return True on success, false on failure (read: error set to 0 means 953 * invalid file size, write: error set to 0 means invalid header) 954 */ 955 bool open(const char* fileName, const RadioDataDesc* data, 956 DebugEnabler* dbg = 0, int* error = 0); 957 958 /** 959 * Write a record to file 960 * @param ts Record timestamp 961 * @param buf Buffer to write 962 * @param len Buffer length in bytes 963 * @param dbg Optional DebugEnabler pointer (show debug on failure) 964 * @param error Optional destination for file operation error code 965 * @return True on success, false on failure (error set to 0 means invalid length) 966 */ 967 bool write(uint64_t ts, const void* buf, uint32_t len, DebugEnabler* dbg = 0, 968 int* error = 0); 969 970 /** 971 * Read a record from file 972 * The method don't check the record length, this must be done by the upper layer 973 * @param ts Record timestamp 974 * @param buffer Destination buffer. It will be resized to read data length 975 * @param dbg Optional DebugEnabler pointer (show debug on failure) 976 * @param error Optional destination for file operation error code 977 * @return True on success (empty buffer means file EOF), 978 * false on failure (error set to 0 means invalid record size) 979 */ 980 bool read(uint64_t& ts, DataBlock& buffer, DebugEnabler* dbg = 0, int* error = 0); 981 982 /** 983 * Terminate data dump, close file 984 * @param dbg Optional DebugEnabler pointer (show terminate message) 985 */ 986 void terminate(DebugEnabler* dbg = 0); 987 988 /** 989 * Convert endiannes 990 * @param buf The buffer to convert 991 * @param bytes Element length in bytes 992 * @return True on success, false if not supported 993 */ 994 static bool fixEndian(DataBlock& buf, unsigned int bytes); 995 996 protected: 997 bool ioError(bool send, DebugEnabler* dbg, int* error, const char* extra); 998 999 bool m_littleEndian; // Machine endiannes 1000 bool m_dropOnError; // Terminate (close file) on error 1001 uint32_t m_chunkSize; // Item size (used to check data validity) 1002 RadioDataDesc m_header; // File header 1003 File m_file; // File to use 1004 DataBlock m_writeBuf; 1005 }; 1006 1007 }; // namespace TelEngine 1008 1009 #endif /* __YATERADIO_H */ 1010 1011 /* vi: set ts=8 sw=4 sts=4 noet: */ 1012