1 /**
2 * zapcard.cpp
3 * This file is part of the YATE Project http://YATE.null.ro
4 *
5 * Zaptel PRI/TDM/FXS/FXO cards signalling and data driver
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 #include <yatephone.h>
23 #include <yatesig.h>
24
25 #ifdef _WINDOWS
26 #error This module is not for Windows
27 #else
28
29 extern "C" {
30 #ifdef HAVE_ZAP
31 #ifdef NEW_ZAPTEL_LOCATION
32 #define __LINUX__
33 #include <zaptel/zaptel.h>
34 #else
35 #include <linux/zaptel.h>
36 #endif
37 #else
38 #include <dahdi/user.h>
39 #endif
40 };
41
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/ioctl.h>
46 #include <fcntl.h>
47
48 using namespace TelEngine;
49 namespace { // anonymous
50
51 class ZapWorkerClient; // Worker thread client (implements process())
52 class ZapWorkerThread; // Worker thread (calls client's process() in a loop)
53 class ZapDevice; // Zaptel I/O device. Implements the interface with the Zaptel driver
54 class ZapInterface; // D-channel signalling interface
55 class ZapSpan; // Signalling span used to create voice circuits
56 class ZapCircuit; // A voice circuit
57 class ZapAnalogCircuit; // A analog circuit
58 class ZapSource; // Data source
59 class ZapConsumer; // Data consumer
60 class ZapModule; // The module
61
62 #define ZAP_ERR_OVERRUN 0x01 // Flags used to filter interface errors
63 #define ZAP_ERR_ABORT 0x02
64
65 #define ZAP_CRC_LEN 2 // The length of the CRC field in signalling packets
66
67 #ifdef HAVE_ZAP
68
69 // alarms
70 #define DAHDI_ALARM_RECOVER ZT_ALARM_RECOVER
71 #define DAHDI_ALARM_LOOPBACK ZT_ALARM_LOOPBACK
72 #define DAHDI_ALARM_RED ZT_ALARM_RED
73 #define DAHDI_ALARM_YELLOW ZT_ALARM_YELLOW
74 #define DAHDI_ALARM_BLUE ZT_ALARM_BLUE
75 #define DAHDI_ALARM_NOTOPEN ZT_ALARM_NOTOPEN
76
77
78 // events
79 #define DAHDI_EVENT_NONE ZT_EVENT_NONE
80 #define DAHDI_EVENT_ONHOOK ZT_EVENT_ONHOOK
81 #define DAHDI_EVENT_RINGOFFHOOK ZT_EVENT_RINGOFFHOOK
82 #define DAHDI_EVENT_WINKFLASH ZT_EVENT_WINKFLASH
83 #define DAHDI_EVENT_ALARM ZT_EVENT_ALARM
84 #define DAHDI_EVENT_NOALARM ZT_EVENT_NOALARM
85 #define DAHDI_EVENT_ABORT ZT_EVENT_ABORT
86 #define DAHDI_EVENT_OVERRUN ZT_EVENT_OVERRUN
87 #define DAHDI_EVENT_BADFCS ZT_EVENT_BADFCS
88 #define DAHDI_EVENT_DIALCOMPLETE ZT_EVENT_DIALCOMPLETE
89 #define DAHDI_EVENT_RINGERON ZT_EVENT_RINGERON
90 #define DAHDI_EVENT_RINGEROFF ZT_EVENT_RINGEROFF
91 #define DAHDI_EVENT_HOOKCOMPLETE ZT_EVENT_HOOKCOMPLETE
92 #define DAHDI_EVENT_BITSCHANGED ZT_EVENT_BITSCHANGED
93 #define DAHDI_EVENT_PULSE_START ZT_EVENT_PULSE_START
94 #define DAHDI_EVENT_TIMER_EXPIRED ZT_EVENT_TIMER_EXPIRED
95 #define DAHDI_EVENT_TIMER_PING ZT_EVENT_TIMER_PING
96 #define DAHDI_EVENT_RINGBEGIN ZT_EVENT_RINGBEGIN
97 #define DAHDI_EVENT_POLARITY ZT_EVENT_POLARITY
98
99 #ifdef ZT_EVENT_REMOVED
100 #define DAHDI_EVENT_REMOVED ZT_EVENT_REMOVED
101 #endif
102
103 #define DAHDI_EVENT_PULSEDIGIT ZT_EVENT_PULSEDIGIT
104 #define DAHDI_EVENT_DTMFDOWN ZT_EVENT_DTMFDOWN
105 #define DAHDI_EVENT_DTMFUP ZT_EVENT_DTMFUP
106 #define DAHDI_EVENT_PULSEDIGIT ZT_EVENT_PULSEDIGIT
107
108 // hook events
109 #define DAHDI_ONHOOK ZT_ONHOOK
110 #define DAHDI_OFFHOOK ZT_OFFHOOK
111 #define DAHDI_WINK ZT_WINK
112 #define DAHDI_FLASH ZT_FLASH
113 #define DAHDI_START ZT_START
114 #define DAHDI_RING ZT_RING
115 #define DAHDI_RINGOFF ZT_RINGOFF
116
117 // flush buffers
118 #define DAHDI_FLUSH_READ ZT_FLUSH_READ
119 #define DAHDI_FLUSH_WRITE ZT_FLUSH_WRITE
120 #define DAHDI_FLUSH_BOTH ZT_FLUSH_BOTH
121 #define DAHDI_FLUSH_EVENT ZT_FLUSH_EVENT
122 #define DAHDI_FLUSH_ALL ZT_FLUSH_ALL
123
124 // formats
125 #define DAHDI_LAW_DEFAULT ZT_LAW_DEFAULT
126 #define DAHDI_LAW_MULAW ZT_LAW_MULAW
127 #define DAHDI_LAW_ALAW ZT_LAW_ALAW
128
129 // dial operations
130 #define DAHDI_DIAL_OP_APPEND ZT_DIAL_OP_APPEND
131 #define DAHDI_DIAL_OP_REPLACE ZT_DIAL_OP_REPLACE
132 #define DAHDI_DIAL_OP_CANCEL ZT_DIAL_OP_CANCEL
133
134 // signalling types
135 #define DAHDI_SIG_NONE ZT_SIG_NONE
136 #define DAHDI_SIG_FXSLS ZT_SIG_FXSLS
137 #define DAHDI_SIG_FXSGS ZT_SIG_FXSGS
138 #define DAHDI_SIG_FXSKS ZT_SIG_FXSKS
139 #define DAHDI_SIG_FXOLS ZT_SIG_FXOLS
140 #define DAHDI_SIG_FXOGS ZT_SIG_FXOGS
141 #define DAHDI_SIG_FXOKS ZT_SIG_FXOKS
142 #define DAHDI_SIG_EM ZT_SIG_EM
143 #define DAHDI_SIG_CLEAR ZT_SIG_CLEAR
144 #define DAHDI_SIG_HDLCRAW ZT_SIG_HDLCRAW
145 #define DAHDI_SIG_HDLCFCS ZT_SIG_HDLCFCS
146 #define DAHDI_SIG_HDLCNET ZT_SIG_HDLCNET
147 #define DAHDI_SIG_SLAVE ZT_SIG_SLAVE
148 #define DAHDI_SIG_SF ZT_SIG_SF
149 #define DAHDI_SIG_CAS ZT_SIG_CAS
150 #define DAHDI_SIG_DACS ZT_SIG_DACS
151 #define DAHDI_SIG_EM_E1 ZT_SIG_EM_E1
152 #define DAHDI_SIG_DACS_RBS ZT_SIG_DACS_RBS
153 #define DAHDI_SIG_HARDHDLC ZT_SIG_HARDHDLC
154
155 // tonedetect
156 #define DAHDI_TONEDETECT_ON ZT_TONEDETECT_ON
157 #define DAHDI_TONEDETECT_MUTE ZT_TONEDETECT_MUTE
158
159 // dtmfs
160 #define DAHDI_MAX_DTMF_BUF ZT_MAX_DTMF_BUF
161 #define DAHDI_TONE_DTMF_0 ZT_TONE_DTMF_0
162 #define DAHDI_TONE_DTMF_1 ZT_TONE_DTMF_1
163 #define DAHDI_TONE_DTMF_2 ZT_TONE_DTMF_2
164 #define DAHDI_TONE_DTMF_3 ZT_TONE_DTMF_3
165 #define DAHDI_TONE_DTMF_4 ZT_TONE_DTMF_4
166 #define DAHDI_TONE_DTMF_5 ZT_TONE_DTMF_5
167 #define DAHDI_TONE_DTMF_6 ZT_TONE_DTMF_6
168 #define DAHDI_TONE_DTMF_7 ZT_TONE_DTMF_7
169 #define DAHDI_TONE_DTMF_8 ZT_TONE_DTMF_8
170 #define DAHDI_TONE_DTMF_9 ZT_TONE_DTMF_9
171 #define DAHDI_TONE_DTMF_s ZT_TONE_DTMF_s
172 #define DAHDI_TONE_DTMF_p ZT_TONE_DTMF_p
173 #define DAHDI_TONE_DTMF_A ZT_TONE_DTMF_A
174 #define DAHDI_TONE_DTMF_B ZT_TONE_DTMF_B
175 #define DAHDI_TONE_DTMF_C ZT_TONE_DTMF_C
176 #define DAHDI_TONE_DTMF_D ZT_TONE_DTMF_D
177
178 // ioctl operations
179 #define DAHDI_SIG_EM ZT_SIG_EM
180 #define DAHDI_GETEVENT ZT_GETEVENT
181 #define DAHDI_SPECIFY ZT_SPECIFY
182 #define DAHDI_SET_BLOCKSIZE ZT_SET_BLOCKSIZE
183 #define DAHDI_SET_BUFINFO ZT_SET_BUFINFO
184 #define DAHDI_SETLAW ZT_SETLAW
185 #define DAHDI_AUDIOMODE ZT_AUDIOMODE
186 #define DAHDI_ECHOCANCEL ZT_ECHOCANCEL
187 #define DAHDI_DIAL ZT_DIAL
188 #define DAHDI_HOOK ZT_HOOK
189 #define DAHDI_TONEDETECT ZT_TONEDETECT
190 #define DAHDI_SETPOLARITY ZT_SETPOLARITY
191 #define DAHDI_SETLINEAR ZT_SETLINEAR
192 #define DAHDI_SET_DIALPARAMS ZT_SET_DIALPARAMS
193 #define DAHDI_GET_PARAMS ZT_GET_PARAMS
194 #define DAHDI_SPANSTAT ZT_SPANSTAT
195 #define DAHDI_GET_DIALPARAMS ZT_GET_DIALPARAMS
196 #define DAHDI_ECHOTRAIN ZT_ECHOTRAIN
197 #define DAHDI_FLUSH ZT_FLUSH
198 #define DAHDI_SENDTONE ZT_SENDTONE
199 #define DAHDI_GETVERSION ZT_GETVERSION
200
201 // policies
202 #define DAHDI_POLICY_IMMEDIATE ZT_POLICY_IMMEDIATE
203
204 // data types
205 #define dahdi_params zt_params
206 #define dahdi_bufferinfo zt_bufferinfo
207 #define dahdi_dialoperation zt_dialoperation
208 #define dahdi_dialparams zt_dialparams
209 #define dahdi_spaninfo zt_spaninfo
210 #define dahdi_versioninfo zt_versioninfo
211
212 #endif
213 // Worker thread client (implements process())
214 class ZapWorkerClient
215 {
216 friend class ZapWorkerThread;
217 public:
~ZapWorkerClient()218 virtual ~ZapWorkerClient() { stop(); }
219 bool running() const;
220 // Return true to tell the worker to call again
221 // Return false to yield
222 virtual bool process() = 0;
223 protected:
ZapWorkerClient()224 inline ZapWorkerClient() : m_thread(0) {}
225 // Start thread if not started
226 bool start(Thread::Priority prio, DebugEnabler* dbg, const String& addr);
227 // Stop thread if started
228 void stop();
229 private:
230 ZapWorkerThread* m_thread;
231 };
232
233 // Worker thread (calls client's process() in a loop)
234 class ZapWorkerThread : public Thread
235 {
236 public:
ZapWorkerThread(ZapWorkerClient * client,const String & addr,Priority prio=Normal)237 inline ZapWorkerThread(ZapWorkerClient* client, const String& addr, Priority prio = Normal)
238 : Thread(s_threadName,prio), m_client(client), m_address(addr)
239 {}
240 virtual ~ZapWorkerThread();
241 // Call client's process() in a loop
242 virtual void run();
243 static const char* s_threadName;
244 private:
245 ZapWorkerClient* m_client;
246 String m_address;
247 };
248
249 // I/O device
250 class ZapDevice : public GenObject
251 {
252 public:
253 // Flags to check alarms
254 enum Alarm {
255 Recover = DAHDI_ALARM_RECOVER, // Recovering from alarm
256 Loopback = DAHDI_ALARM_LOOPBACK, // In loopback
257 Red = DAHDI_ALARM_RED, // Interface is down
258 Yellow = DAHDI_ALARM_YELLOW, // Remote peer doesn't see us
259 Blue = DAHDI_ALARM_BLUE, // We don't see the remote peer
260 NotOpen = DAHDI_ALARM_NOTOPEN
261 };
262
263 // List of events
264 enum Event {
265 None = DAHDI_EVENT_NONE,
266 OnHook = DAHDI_EVENT_ONHOOK,
267 OffHookRing = DAHDI_EVENT_RINGOFFHOOK,
268 WinkFlash = DAHDI_EVENT_WINKFLASH,
269 Alarm = DAHDI_EVENT_ALARM,
270 NoAlarm = DAHDI_EVENT_NOALARM,
271 HdlcAbort = DAHDI_EVENT_ABORT,
272 HdlcOverrun = DAHDI_EVENT_OVERRUN,
273 BadFCS = DAHDI_EVENT_BADFCS,
274 DialComplete = DAHDI_EVENT_DIALCOMPLETE,
275 RingerOn = DAHDI_EVENT_RINGERON,
276 RingerOff = DAHDI_EVENT_RINGEROFF,
277 HookComplete = DAHDI_EVENT_HOOKCOMPLETE,
278 BitsChanged = DAHDI_EVENT_BITSCHANGED, // Bits changing on a CAS/User channel
279 PulseStart = DAHDI_EVENT_PULSE_START, // Beginning of a pulse coming on its way
280 Timeout = DAHDI_EVENT_TIMER_EXPIRED,
281 TimerPing = DAHDI_EVENT_TIMER_PING,
282 RingBegin = DAHDI_EVENT_RINGBEGIN,
283 Polarity = DAHDI_EVENT_POLARITY, // Polarity reversal event
284 #ifdef DAHDI_EVENT_REMOVED
285 Removed = DAHDI_EVENT_REMOVED,
286 #endif
287 // These are event masks
288 PulseDigit = DAHDI_EVENT_PULSEDIGIT, // This is OR'd with the digit received
289 DtmfDown = DAHDI_EVENT_DTMFDOWN, // Ditto for DTMF key down event
290 DtmfUp = DAHDI_EVENT_DTMFUP, // Ditto for DTMF key up event
291 DigitEvent = DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFDOWN | DAHDI_EVENT_DTMFUP
292 };
293
294 // List of hook to send events
295 enum HookEvent {
296 HookOn = DAHDI_ONHOOK,
297 HookOff = DAHDI_OFFHOOK,
298 HookWink = DAHDI_WINK,
299 HookFlash = DAHDI_FLASH,
300 HookStart = DAHDI_START,
301 HookRing = DAHDI_RING,
302 HookRingOff = DAHDI_RINGOFF
303 };
304
305 // Rx Hook states, not exported from zaptel.h in user mode
306 enum RxSigState {
307 RxSigOnHook = 0,
308 RxSigOffHook,
309 RxSigStart,
310 RxSigRing,
311 RxSigInitial
312 };
313
314 // List of valid IOCTL requests
315 enum IoctlRequest {
316 SetChannel = 0, // Specify a channel number for an opened device
317 SetBlkSize = 1, // Set data I/O block size
318 SetBuffers = 2, // Set buffers
319 SetFormat = 3, // Set format
320 SetAudioMode = 4, // Set audio mode
321 SetEchoCancel = 5, // Set echo cancel
322 SetDial = 6, // Append, replace, or cancel a dial string
323 SetHook = 7, // Set Hookswitch Status
324 #ifdef DAHDI_TONEDETECT
325 SetToneDetect = 8, // Set tone detection
326 #else
327 SetToneDetect = 101,
328 #endif
329 SetPolarity = 10, // Set line polarity
330 SetLinear = 11, // Temporarily set the channel to operate in linear mode
331 SetDialParams = 12, // Set dialing parameters
332 GetParams = 20, // Get device (channel) parameters
333 GetEvent = 21, // Get events from device
334 GetInfo = 22, // Get device status
335 GetVersion = 23, // Get version
336 GetDialParams = 24, // Get dialing parameters
337 StartEchoTrain = 30, // Start echo training
338 FlushBuffers = 31, // Flush buffer(s) and stop I/O
339 SendTone = 32, // Send tone
340 };
341
342 enum FlushTarget {
343 FlushRead = DAHDI_FLUSH_READ,
344 FlushWrite = DAHDI_FLUSH_WRITE,
345 FlushRdWr = DAHDI_FLUSH_BOTH,
346 FlushEvent = DAHDI_FLUSH_EVENT,
347 FlushAll = DAHDI_FLUSH_ALL,
348 };
349
350 // Zaptel formats
351 enum Format {
352 Slin = -1,
353 Default = DAHDI_LAW_DEFAULT,
354 Mulaw = DAHDI_LAW_MULAW,
355 Alaw = DAHDI_LAW_ALAW
356 };
357
358 // Device type: D-channel, voice/data circuit or control
359 enum Type {
360 DChan,
361 E1,
362 T1,
363 BRI,
364 FXO,
365 FXS,
366 Control,
367 TypeUnknown
368 };
369
370 // Dial operations
371 enum DialOperation {
372 DialAppend = DAHDI_DIAL_OP_APPEND,
373 DialReplace = DAHDI_DIAL_OP_REPLACE,
374 DialCancel = DAHDI_DIAL_OP_CANCEL
375 };
376
377 // Create a device used to query the driver (chan=0) or a zaptel channel
378 // Open it if requested
379 ZapDevice(unsigned int chan, bool disableDbg = true, bool open = true);
380 ZapDevice(Type t, SignallingComponent* dbg, unsigned int chan,
381 unsigned int circuit);
382 virtual ~ZapDevice();
type() const383 inline Type type() const
384 { return m_type; }
zapsig() const385 inline int zapsig() const
386 { return m_zapsig; }
owner() const387 inline SignallingComponent* owner() const
388 { return m_owner; }
address() const389 inline const String& address() const
390 { return m_address; }
valid() const391 inline bool valid() const
392 { return m_handle >= 0; }
channel() const393 inline unsigned int channel() const
394 { return m_channel; }
span() const395 inline int span() const
396 { return m_span; }
spanPos() const397 inline int spanPos() const
398 { return m_spanPos; }
399 void channel(unsigned int chan, unsigned int circuit);
alarms() const400 inline int alarms() const
401 { return m_alarms; }
alarmsText() const402 inline const String& alarmsText() const
403 { return m_alarmsText; }
canRead() const404 inline bool canRead() const
405 { return m_canRead; }
event() const406 inline bool event() const
407 { return m_event || m_savedEvent; }
zapDevName() const408 inline const char* zapDevName() const
409 { return (m_type != Control) ? s_zapDevName : s_zapCtlName; }
410 // Get driver/chan format
zapName() const411 inline const String& zapName() const
412 { return m_zapName; }
413 // Open the device. Specify channel to use.
414 // Circuit: Set block size (ignore numbufs)
415 // Interface: Check channel mode. Set buffers
416 bool open(unsigned int numbufs, unsigned int bufsize);
417 // Close device. Reset handle
418 void close();
419 // Set data format. Fails if called for an interface
420 bool setFormat(Format format);
421 // Set/unset tone detection
422 bool setDtmfDetect(bool detect);
423 // Update echo canceller (disable if taps is 0)
424 bool setEchoCancel(bool enable, unsigned int taps);
425 // Start echo canceller training for a given period of time (in miliseconds)
426 bool startEchoTrain(unsigned int period);
427 // Enable polling of off-hook state, call only for passive FXO
initHook()428 inline void initHook()
429 { m_rxHookSig = RxSigInitial; }
430 // Poll the hook state and save event since a FXO does not generate events
431 void pollHook();
432 // Send hook events
433 bool sendHook(HookEvent event);
434 // Send DTMFs events using dialing or tone structure
435 // dtmf: true - send DTMF (tone dialing), false - send MF (pulse dialing)
436 // op: The dial operation to use
437 // allDigits: true to send all digits at once
438 // useTone: Used only if 'allDigits' is false and 'dtmf' is true
439 bool sendDtmf(const char* tone, bool dtmf = true, DialOperation op = DialAppend,
440 bool allDigits = true, bool useTone = false);
441 // Send DTMF event using tone structure
442 bool sendDtmf(char tone);
443 // Get an event. Return 0 if no events. Set digit if the event is a DTMF/PULSE
444 int getEvent(char& digit);
445 // Check alarms from this device. Return true if alarms changed
446 bool checkAlarms();
447 // Reset alarms
448 void resetAlarms();
449 // Set clear channel
setLinear(int val,int level=DebugWarn)450 inline bool setLinear(int val, int level = DebugWarn)
451 { return ioctl(SetLinear,&val,level); }
452 // Set line polarity
setPolarity(int val,int level=DebugWarn)453 inline bool setPolarity(int val, int level = DebugWarn)
454 { return ioctl(SetPolarity,&val,level); }
455 // Flush read and write buffers
456 bool flushBuffers(FlushTarget target = FlushAll);
457 // Check if received data. Wait usec microseconds before returning
458 bool select(unsigned int usec);
459 // Receive data. Return -1 on error or the number of bytes read
460 // If -1 is returned, the caller should check if m_event is set
461 int recv(void* buffer, int len);
462 // Send data. Return -1 on error or the number of bytes written
463 int send(const void* buffer, int len);
464 // Send data. Return -1 on error or the number of bytes written
write(const void * buffer,int len)465 inline int write(const void* buffer, int len)
466 { return ::write(m_handle,buffer,len); }
467 // Get driver version and echo canceller
468 bool getVersion(NamedList& dest);
469 // Get driver version and echo canceller
470 bool getSpanInfo(int span, NamedList& dest, int* spans = 0);
471 // Get channel parameters
472 bool getChanParams(NamedList& dest);
473 // Set/get dial parameters (DTMF/MF length)
474 bool dialParams(bool set, int& toneLen, int& mfLen);
475 // Zaptel device names and headers for status
476 static const char* s_zapCtlName;
477 static const char* s_zapDevName;
478 protected:
canRetry()479 inline bool canRetry()
480 { return errno == EAGAIN || errno == EINTR; }
481 // Make IOCTL requests on this device
482 bool ioctl(IoctlRequest request, void* param, int level = DebugWarn);
483 private:
484 Type m_type; // Device type
485 int m_zapsig; // Zaptel signalling type
486 SignallingComponent* m_owner; // Signalling component owning this device
487 String m_name; // Additional debug name for circuits
488 String m_address; // User address (interface or circuit)
489 String m_zapName; // Zaptel name (Zaptel/channel)
490 int m_handle; // The handler
491 unsigned int m_channel; // The channel this file is used for
492 int m_span; // Span this device's channel belongs to
493 int m_spanPos; // Physical channel inside span
494 int m_alarms; // Device alarms flag
495 int m_rxHookSig; // Keep hook status for bridged lines
496 int m_savedEvent; // Event saved asynchronously for later
497 String m_alarmsText; // Alarms text
498 bool m_canRead; // True if there is data to read
499 bool m_event; // True if an event occurred when recv/select
500 bool m_readError; // Flag used to print read errors
501 bool m_writeError; // Flag used to print write errors
502 bool m_selectError; // Flag used to print select errors
503 fd_set m_rdfds;
504 fd_set m_errfds;
505 struct timeval m_tv;
506 };
507
508 // D-channel signalling interface
509 class ZapInterface : public SignallingInterface, public ZapWorkerClient
510 {
511 public:
512 ZapInterface(const NamedList& params);
513 virtual ~ZapInterface();
valid() const514 inline bool valid() const
515 { return m_device.valid() && running(); }
516 // Initialize interface. Return false on failure
517 bool init(ZapDevice::Type type, unsigned int code, unsigned int channel,
518 const NamedList& config, const NamedList& defaults, const NamedList& params);
519 // Remove links. Dispose memory
destruct()520 virtual void destruct()
521 { cleanup(true); }
522 // Get this object or an object from the base class
523 virtual void* getObject(const String& name) const;
524 // Send signalling packet
525 virtual bool transmitPacket(const DataBlock& packet, bool repeat, PacketType type);
526 // Interface control. Open device and start worker when enabled, cleanup when disabled
527 virtual bool control(Operation oper, NamedList* params = 0);
528 // Process incoming data
529 virtual bool process();
530 // Called by the factory to create Zaptel interfaces or spans
531 static SignallingComponent* create(const String& type, NamedList& name);
532 protected:
533 // Check if received any data in the last interval. Notify receiver
534 virtual void timerTick(const Time& when);
535 // Check for device events. Notify receiver
536 void checkEvents();
537 private:
cleanup(bool release)538 inline void cleanup(bool release) {
539 control(Disable,0);
540 attach(0);
541 if (release)
542 RefObject::destruct();
543 }
544
545 ZapDevice m_device; // The device
546 Thread::Priority m_priority; // Worker thread priority
547 unsigned char m_errorMask; // Error mask to filter received error events
548 unsigned int m_numbufs; // The number of buffers used by the channel
549 unsigned int m_bufsize; // The buffer size
550 unsigned char* m_buffer; // Read buffer
551 bool m_readOnly; // Read only interface
552 bool m_sendReadOnly; // Print send attempt on readonly interface error
553 int m_notify; // Notify receiver on channel non idle (0: success. 1: not notified. 2: notified)
554 SignallingTimer m_timerRxUnder; // RX underrun notification
555 bool m_down; // Interface status
556 };
557
558 // Signalling span used to create voice circuits
559 class ZapSpan : public SignallingCircuitSpan
560 {
561 public:
ZapSpan(const NamedList & params)562 inline ZapSpan(const NamedList& params)
563 : SignallingCircuitSpan(params.getValue("debugname"),
564 static_cast<SignallingCircuitGroup*>(params.getObject("SignallingCircuitGroup")))
565 {}
~ZapSpan()566 virtual ~ZapSpan()
567 {}
568 // Create circuits. Insert them into the group
569 bool init(ZapDevice::Type type, unsigned int offset,
570 const NamedList& config, const NamedList& defaults, const NamedList& params);
571 };
572
573 // A voice circuit
574 class ZapCircuit : public SignallingCircuit, public ZapWorkerClient
575 {
576 public:
577 ZapCircuit(ZapDevice::Type type, unsigned int code, unsigned int channel,
578 ZapSpan* span, const NamedList& config, const NamedList& defaults,
579 const NamedList& params);
~ZapCircuit()580 virtual ~ZapCircuit()
581 { cleanup(false); }
destroyed()582 virtual void destroyed()
583 { cleanup(true); }
584 // Change circuit status. Clear events on status change
585 // New status is Connect: Open device. Create source/consumer. Start worker
586 // Cleanup on disconnect
587 virtual bool status(Status newStat, bool sync = false);
588 // Update data format for zaptel device and source/consumer
589 virtual bool updateFormat(const char* format, int direction);
590 // Setup echo canceller or start echo canceller training
591 virtual bool setParam(const String& param, const String& value);
592 // Get circuit data
593 virtual bool getParam(const String& param, String& value) const;
594 // Get this circuit or source/consumer
595 virtual void* getObject(const String& name) const;
596 // Process incoming data
597 virtual bool process();
598 // Send an event
599 virtual bool sendEvent(SignallingCircuitEvent::Type type, NamedList* params = 0);
600 // Consume data sent by the consumer
601 void consume(const DataBlock& data);
602 protected:
603 // Close device. Stop worker. Remove source consumer. Change status. Release memory if requested
604 // Reset echo canceller and tone detector if the device is not closed
605 void cleanup(bool release, Status stat = Missing, bool stop = true);
606 // Update format, echo canceller, dtmf detection
607 bool setFormat(ZapDevice::Format format);
608 // Get and process some events
609 void checkEvents();
610 // Process additional events. Return false if not processed
processEvent(int event,char c=0)611 virtual bool processEvent(int event, char c = 0)
612 { return false; }
613 // Create source buffer and data source and consumer
614 void createData();
615 // Enqueue received events
616 bool enqueueEvent(SignallingCircuitEvent* event);
617 bool enqueueEvent(int event, SignallingCircuitEvent::Type type);
618 // Enqueue received digits
619 bool enqueueDigit(bool tone, char digit);
620
621 ZapDevice m_device; // The device
622 ZapDevice::Type m_type; // Circuit type
623 ZapDevice::Format m_format; // The data format
624 String m_specialMode; // Special test mode
625 bool m_echoCancel; // Echo canceller state
626 bool m_crtEchoCancel; // Current echo canceller state
627 unsigned int m_echoTaps; // Echo cancel taps
628 unsigned int m_echoTrain; // Echo canceller's train period in miliseconds
629 bool m_dtmfDetect; // Dtmf detection flag
630 bool m_crtDtmfDetect; // Current dtmf detection state
631 bool m_canSend; // Not a read only circuit
632 unsigned char m_idleValue; // Value used to fill incomplete source buffer
633 Thread::Priority m_priority; // Worker thread priority
634 ZapSource* m_source; // The data source
635 ZapConsumer* m_consumer; // The data consumer
636 DataBlock m_sourceBuffer; // Data source buffer
637 DataBlock m_consBuffer; // Data consumer buffer
638 unsigned int m_buflen; // Data block length
639 unsigned int m_consBufMax; // Max consumer buffer length
640 unsigned int m_consErrors; // Consumer. Total number of send failures
641 unsigned int m_consErrorBytes; // Consumer. Total number of lost bytes
642 unsigned int m_consTotal; // Consumer. Total number of bytes transferred
643 int m_errno; // Last write error
644 };
645
646 // An analog circuit
647 class ZapAnalogCircuit : public ZapCircuit
648 {
649 public:
ZapAnalogCircuit(ZapDevice::Type type,unsigned int code,unsigned int channel,ZapSpan * span,const NamedList & config,const NamedList & defaults,const NamedList & params)650 inline ZapAnalogCircuit(ZapDevice::Type type, unsigned int code, unsigned int channel,
651 ZapSpan* span, const NamedList& config, const NamedList& defaults,
652 const NamedList& params)
653 : ZapCircuit(type,code,channel,span,config,defaults,params),
654 m_hook(true)
655 {}
~ZapAnalogCircuit()656 virtual ~ZapAnalogCircuit()
657 {}
658 // Change circuit status. Clear events on status change
659 // Reserved: Open device and start worker if old status is not Connected
660 // Connect: Create source/consumer
661 // Cleanup on disconnect
662 virtual bool status(Status newStat, bool sync);
663 // Get circuit data
664 virtual bool getParam(const String& param, String& value) const;
665 // Set line polarity
666 virtual bool setParam(const String& param, const String& value);
667 // Send an event
668 virtual bool sendEvent(SignallingCircuitEvent::Type type, NamedList* params = 0);
669 // Process incoming data
670 virtual bool process();
671 protected:
672 // Process additional events. Return false if not processed
673 virtual bool processEvent(int event, char c = 0);
674 // Change hook state if different
675 void changeHook(bool hook);
676
677 bool m_hook; // The remote end's hook status
678 };
679
680 // Data source
681 class ZapSource : public DataSource
682 {
683 public:
684 ZapSource(ZapCircuit* circuit, const char* format);
685 virtual ~ZapSource();
changeFormat(const char * format)686 inline void changeFormat(const char* format)
687 { m_format = format; }
688 private:
689 String m_address;
690 };
691
692 // Data consumer
693 class ZapConsumer : public DataConsumer
694 {
695 friend class ZapCircuit;
696 public:
697 ZapConsumer(ZapCircuit* circuit, const char* format);
698 virtual ~ZapConsumer();
changeFormat(const char * format)699 inline void changeFormat(const char* format)
700 { m_format = format; }
Consume(const DataBlock & data,unsigned long tStamp,unsigned long flags)701 virtual unsigned long Consume(const DataBlock& data, unsigned long tStamp, unsigned long flags)
702 { if (m_circuit) m_circuit->consume(data); return invalidStamp(); }
703 private:
704 ZapCircuit* m_circuit;
705 String m_address;
706 };
707
708 // The Zaptel module
709 class ZapModule : public Module
710 {
711 public:
712 // Additional module commands
713 enum StatusCommands {
714 ZapSpans = 0, // Show all zaptel spans
715 ZapChannels = 1, // Show all configured zaptel channels
716 ZapChannelsAll = 2, // Show all zaptel channels
717 StatusCmdCount = 3
718 };
719 ZapModule();
720 ~ZapModule();
prefix()721 inline const String& prefix()
722 { return m_prefix; }
723 void append(ZapDevice* dev);
724 void remove(ZapDevice* dev);
openClose(bool open)725 inline void openClose(bool open) {
726 Lock lock(this);
727 if (open)
728 m_active++;
729 else
730 m_active--;
731 }
732 virtual void initialize();
733 // Find a device by its Zaptel channel
734 ZapDevice* findZaptelChan(int chan);
735 // Additional module status commands
736 static String s_statusCmd[StatusCmdCount];
737 protected:
738 virtual bool received(Message& msg, int id);
739 virtual void statusModule(String& str);
740 virtual void statusParams(String& str);
741 virtual void statusDetail(String& str);
742 virtual bool commandComplete(Message& msg, const String& partLine,
743 const String& partWord);
744 private:
745 bool m_init; // Already initialized flag
746 String m_prefix; // Module prefix
747 String m_statusCmd; // Status command for this module (status Zaptel)
748 ObjList m_devices; // Device list
749 // Statistics
750 unsigned int m_count; // The number of devices in the list
751 unsigned int m_active; // The number of active(opened) devices
752 };
753
754
755 /**
756 * Module data and functions
757 */
758 static ZapModule plugin;
759 YSIGFACTORY2(ZapInterface); // Factory used to create zaptel interfaces and spans
760 static Mutex s_ifaceNotifyMutex(true,"ZapCard::notify"); // ZapInterface: lock recv data notification counter
761 static Mutex s_sourceAccessMutex(false,"ZapCard::source"); // ZapSource access to pointers
762 static const char* s_chanParamsHdr = "format=Type|ZaptelType|Span|SpanPos|Alarms|UsedBy";
763 static const char* s_spanParamsHdr = "format=Channels|Total|Alarms|Name|Description";
764
765 // Get a boolean value from received parameters or other sections in config
766 // Priority: parameters, config, defaults
getBoolValue(const char * param,const NamedList & config,const NamedList & defaults,const NamedList & params,bool defVal=false)767 static inline bool getBoolValue(const char* param, const NamedList& config,
768 const NamedList& defaults, const NamedList& params, bool defVal = false)
769 {
770 defVal = config.getBoolValue(param,defaults.getBoolValue(param,defVal));
771 return params.getBoolValue(param,defVal);
772 }
773
sendModuleUpdate(const String & notif,const String & device,bool & notifStat,int status=0)774 static void sendModuleUpdate(const String& notif, const String& device, bool& notifStat, int status = 0)
775 {
776 Message* msg = new Message("module.update");
777 msg->addParam("module",plugin.name());
778 msg->addParam("interface",device);
779 msg->addParam("notify",notif);
780 if(notifStat && status == SignallingInterface::LinkUp) {
781 notifStat = false;
782 Engine::enqueue(msg);
783 return;
784 }
785 if (!notifStat && status == SignallingInterface::LinkDown) {
786 notifStat = true;
787 Engine::enqueue(msg);
788 return;
789 }
790 if (notif == "alarm") {
791 if (status == ZapDevice::Yellow)
792 msg->addParam("notify","RAI");
793 if (status == ZapDevice::Blue)
794 msg->addParam("notify","AIS");
795 Engine::enqueue(msg);
796 return;
797 }
798 TelEngine::destruct(msg);
799 }
800
801 /**
802 * ZapWorkerClient
803 */
running() const804 bool ZapWorkerClient::running() const
805 {
806 return m_thread && m_thread->running();
807 }
808
start(Thread::Priority prio,DebugEnabler * dbg,const String & addr)809 bool ZapWorkerClient::start(Thread::Priority prio, DebugEnabler* dbg, const String& addr)
810 {
811 if (!m_thread)
812 m_thread = new ZapWorkerThread(this,addr,prio);
813 if (m_thread->running())
814 return true;
815 if (m_thread->startup())
816 return true;
817 m_thread->cancel(true);
818 m_thread = 0;
819 Debug(dbg,DebugWarn,"Failed to start %s for %s [%p]",
820 ZapWorkerThread::s_threadName,addr.c_str(),dbg);
821 return false;
822 }
823
stop()824 void ZapWorkerClient::stop()
825 {
826 if (!m_thread)
827 return;
828 m_thread->cancel();
829 while (m_thread)
830 Thread::yield();
831 }
832
833 /**
834 * ZapWorkerThread
835 */
836 const char* ZapWorkerThread::s_threadName = "Zap Worker";
837
~ZapWorkerThread()838 ZapWorkerThread::~ZapWorkerThread()
839 {
840 DDebug(&plugin,DebugAll,"%s is terminated for client (%p): %s",
841 s_threadName,m_client,m_address.c_str());
842 if (m_client)
843 m_client->m_thread = 0;
844 }
845
run()846 void ZapWorkerThread::run()
847 {
848 if (!m_client)
849 return;
850 DDebug(&plugin,DebugAll,"%s is running for client (%p): %s",
851 s_threadName,m_client,m_address.c_str());
852 while (true) {
853 if (m_client->process())
854 Thread::check(true);
855 else
856 Thread::yield(true);
857 }
858 }
859
860
861 /**
862 * ZapDevice
863 */
864 static TokenDict s_alarms[] = {
865 {"recover", ZapDevice::Recover},
866 {"loopback", ZapDevice::Loopback},
867 {"yellow", ZapDevice::Yellow},
868 {"red", ZapDevice::Red},
869 {"blue", ZapDevice::Blue},
870 {"not-open", ZapDevice::NotOpen},
871 {0,0}
872 };
873
874 // Zaptel signalling type
875 static TokenDict s_zaptelSig[] = {
876 {"NONE", DAHDI_SIG_NONE}, // Channel not configured
877 {"FXSLS", DAHDI_SIG_FXSLS},
878 {"FXSGS", DAHDI_SIG_FXSGS},
879 {"FXSKS", DAHDI_SIG_FXSKS},
880 {"FXOLS", DAHDI_SIG_FXOLS},
881 {"FXOGS", DAHDI_SIG_FXOGS},
882 {"FXOKS", DAHDI_SIG_FXOKS},
883 {"E&M", DAHDI_SIG_EM}, // Ear & mouth
884 {"CLEAR", DAHDI_SIG_CLEAR}, // Clear channel
885 {"HDLCRAW", DAHDI_SIG_HDLCRAW}, // Raw unchecked HDLC
886 {"HDLCFCS", DAHDI_SIG_HDLCFCS}, // HDLC with FCS calculation
887 {"HDLCNET", DAHDI_SIG_HDLCNET}, // HDLC Network
888 {"SLAVE", DAHDI_SIG_SLAVE}, // Slave to another channel
889 {"SF", DAHDI_SIG_SF}, // Single Freq. tone only, no sig bits
890 {"CAS", DAHDI_SIG_CAS}, // Just get bits
891 {"DACS", DAHDI_SIG_DACS}, // Cross connect
892 {"EM_E1", DAHDI_SIG_EM_E1}, // E1 E&M Variation
893 {"DACS_RBS", DAHDI_SIG_DACS_RBS}, // Cross connect w/ RBS
894 {"HARDHDLC", DAHDI_SIG_HARDHDLC},
895 {0,0}
896 };
897
898 #define MAKE_NAME(x) { #x, ZapDevice::x }
899 static TokenDict s_events[] = {
900 MAKE_NAME(None),
901 MAKE_NAME(OnHook),
902 MAKE_NAME(OffHookRing),
903 MAKE_NAME(WinkFlash),
904 MAKE_NAME(Alarm),
905 MAKE_NAME(NoAlarm),
906 MAKE_NAME(HdlcAbort),
907 MAKE_NAME(HdlcOverrun),
908 MAKE_NAME(BadFCS),
909 MAKE_NAME(DialComplete),
910 MAKE_NAME(RingerOn),
911 MAKE_NAME(RingerOff),
912 MAKE_NAME(HookComplete),
913 MAKE_NAME(BitsChanged),
914 MAKE_NAME(PulseStart),
915 MAKE_NAME(Timeout),
916 MAKE_NAME(TimerPing),
917 MAKE_NAME(RingBegin),
918 MAKE_NAME(Polarity),
919 MAKE_NAME(PulseDigit),
920 MAKE_NAME(DtmfDown),
921 MAKE_NAME(DtmfUp),
922 MAKE_NAME(DigitEvent),
923 #ifdef DAHDI_EVENT_REMOVED
924 MAKE_NAME(Removed),
925 #endif
926 {0,0}
927 };
928
929 static TokenDict s_hookEvents[] = {
930 MAKE_NAME(HookOn),
931 MAKE_NAME(HookOff),
932 MAKE_NAME(HookWink),
933 MAKE_NAME(HookFlash),
934 MAKE_NAME(HookStart),
935 MAKE_NAME(HookRing),
936 MAKE_NAME(HookRingOff),
937 {0,0}
938 };
939
940 static TokenDict s_ioctl_request[] = {
941 MAKE_NAME(SetChannel),
942 MAKE_NAME(SetBlkSize),
943 MAKE_NAME(SetBuffers),
944 MAKE_NAME(SetFormat),
945 MAKE_NAME(SetAudioMode),
946 MAKE_NAME(SetEchoCancel),
947 MAKE_NAME(SetDial),
948 MAKE_NAME(SetHook),
949 MAKE_NAME(SetToneDetect),
950 MAKE_NAME(SetPolarity),
951 MAKE_NAME(SetLinear),
952 MAKE_NAME(SetDialParams),
953 MAKE_NAME(GetParams),
954 MAKE_NAME(GetEvent),
955 MAKE_NAME(GetInfo),
956 MAKE_NAME(GetVersion),
957 MAKE_NAME(GetDialParams),
958 MAKE_NAME(StartEchoTrain),
959 MAKE_NAME(FlushBuffers),
960 MAKE_NAME(SendTone),
961 {0,0}
962 };
963
964 static TokenDict s_types[] = {
965 MAKE_NAME(DChan),
966 MAKE_NAME(E1),
967 MAKE_NAME(T1),
968 MAKE_NAME(BRI),
969 MAKE_NAME(FXO),
970 MAKE_NAME(FXS),
971 MAKE_NAME(Control),
972 {"not-used", ZapDevice::TypeUnknown},
973 {0,0}
974 };
975 #undef MAKE_NAME
976
977 static TokenDict s_formats[] = {
978 {"slin", ZapDevice::Slin},
979 {"default", ZapDevice::Default},
980 {"mulaw", ZapDevice::Mulaw},
981 {"alaw", ZapDevice::Alaw},
982 {0,0}
983 };
984 #ifdef HAVE_ZAP
985 const char* ZapDevice::s_zapCtlName = "/dev/zap/ctl";
986 const char* ZapDevice::s_zapDevName = "/dev/zap/channel";
987 #else
988 const char* ZapDevice::s_zapCtlName = "/dev/dahdi/ctl";
989 const char* ZapDevice::s_zapDevName = "/dev/dahdi/channel";
990 #endif
ZapDevice(Type t,SignallingComponent * dbg,unsigned int chan,unsigned int circuit)991 ZapDevice::ZapDevice(Type t, SignallingComponent* dbg, unsigned int chan,
992 unsigned int circuit)
993 : m_type(t),
994 m_zapsig(-1),
995 m_owner(dbg),
996 m_handle(-1),
997 m_channel(chan),
998 m_span(-1),
999 m_spanPos(-1),
1000 m_alarms(NotOpen),
1001 m_rxHookSig(-1),
1002 m_savedEvent(0),
1003 m_canRead(false),
1004 m_event(false),
1005 m_readError(false),
1006 m_writeError(false),
1007 m_selectError(false)
1008 {
1009 XDebug(&plugin,DebugNote,"ZapDevice type=%s chan=%u owner=%s cic=%u [%p]",
1010 lookup(t,s_types),chan,dbg?dbg->debugName():"",circuit,this);
1011 close();
1012 this->channel(chan,circuit);
1013 if (m_type == Control || m_type == TypeUnknown) {
1014 m_owner = 0;
1015 return;
1016 }
1017 plugin.append(this);
1018 }
1019
1020 // Create a device used to query the driver (chan=0) or a zaptel channel
ZapDevice(unsigned int chan,bool disableDbg,bool open)1021 ZapDevice::ZapDevice(unsigned int chan, bool disableDbg, bool open)
1022 : m_type(chan ? TypeUnknown : Control),
1023 m_zapsig(-1),
1024 m_owner(0),
1025 m_handle(-1),
1026 m_channel(chan),
1027 m_span(-1),
1028 m_spanPos(-1),
1029 m_alarms(NotOpen),
1030 m_rxHookSig(-1),
1031 m_savedEvent(0),
1032 m_canRead(false),
1033 m_event(false),
1034 m_readError(false),
1035 m_writeError(false),
1036 m_selectError(false)
1037 {
1038 XDebug(&plugin,DebugNote,"ZapDevice(ZaptelQuery) type=%s chan=%u [%p]",
1039 lookup(m_type,s_types),chan,this);
1040 close();
1041 channel(chan,0);
1042 m_owner = new SignallingCircuitGroup(0,0,"ZaptelQuery");
1043 if (disableDbg)
1044 m_owner->debugEnabled(false);
1045 if (open)
1046 this->open(0,160);
1047 }
1048
~ZapDevice()1049 ZapDevice::~ZapDevice()
1050 {
1051 XDebug(&plugin,DebugNote,"ZapDevice destruct type=%s chan=%u owner=%s [%p]",
1052 lookup(m_type,s_types),m_channel,m_owner?m_owner->debugName():"",this);
1053 if (m_type == Control || m_type == TypeUnknown)
1054 TelEngine::destruct(m_owner);
1055 plugin.remove(this);
1056 close();
1057 }
1058
channel(unsigned int chan,unsigned int circuit)1059 void ZapDevice::channel(unsigned int chan, unsigned int circuit)
1060 {
1061 m_channel = chan;
1062 m_zapName << plugin.name() << "/" << m_channel;
1063 m_address << (m_owner ? m_owner->debugName() : "");
1064 if (m_type != DChan && m_type != Control && m_address) {
1065 m_name << "ZapCircuit(" << circuit << "). ";
1066 m_address << "/" << circuit;
1067 }
1068 }
1069
1070 // Open the device. Specify channel to use.
1071 // Circuit: Set block size
1072 // Interface: Check channel mode. Set buffers
open(unsigned int numbufs,unsigned int bufsize)1073 bool ZapDevice::open(unsigned int numbufs, unsigned int bufsize)
1074 {
1075 close();
1076
1077 if (m_type == DChan || m_type == Control)
1078 m_handle = ::open(zapDevName(),O_RDWR,0600);
1079 else
1080 m_handle = ::open(zapDevName(),O_RDWR|O_NONBLOCK);
1081 if (m_handle < 0) {
1082 Debug(m_owner,DebugWarn,"%sFailed to open '%s'. %d: %s [%p]",
1083 m_name.safe(),zapDevName(),errno,::strerror(errno),m_owner);
1084 return false;
1085 }
1086
1087 // Done if opening the main zaptel device
1088 if (m_type == Control)
1089 return true;
1090
1091 // Notify plugin if opened for normal (not for query properties) use
1092 if (m_type != TypeUnknown)
1093 plugin.openClose(true);
1094
1095 m_alarms = 0;
1096 m_alarmsText = "";
1097 while (true) {
1098 // Specify the channel to use
1099 if (!ioctl(SetChannel,&m_channel))
1100 break;
1101
1102 struct dahdi_params par;
1103 if (!ioctl(GetParams,&par))
1104 break;
1105
1106 m_span = par.spanno;
1107 m_spanPos = par.chanpos;
1108 m_zapsig = par.sigtype;
1109
1110 checkAlarms();
1111
1112 if (m_type != DChan) {
1113 if (bufsize && !ioctl(SetBlkSize,&bufsize))
1114 break;
1115 DDebug(m_owner,DebugAll,"%sBlock size set to %u on channel %u [%p]",
1116 m_name.safe(),bufsize,m_channel,m_owner);
1117 return true;
1118 }
1119
1120 // Open for an interface
1121 // Check channel mode
1122 if (par.sigtype != DAHDI_SIG_HDLCFCS && par.sigtype != DAHDI_SIG_HARDHDLC) {
1123 Debug(m_owner,DebugWarn,"Channel %u is not in '%s' or '%s' mode [%p]",
1124 m_channel,lookup(DAHDI_SIG_HDLCFCS,s_zaptelSig),
1125 lookup(DAHDI_SIG_HARDHDLC,s_zaptelSig),m_owner);
1126 break;
1127 }
1128 // Set buffers
1129 struct dahdi_bufferinfo bi;
1130 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
1131 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
1132 bi.numbufs = numbufs;
1133 bi.bufsize = bufsize;
1134 if (ioctl(SetBuffers,&bi))
1135 DDebug(m_owner,DebugAll,"%snumbufs=%u bufsize=%u on channel %u [%p]",
1136 m_name.safe(),numbufs,bufsize,m_channel,m_owner);
1137 return true;
1138 }
1139 close();
1140 return false;
1141 }
1142
1143 // Close device. Reset handle
close()1144 void ZapDevice::close()
1145 {
1146 m_alarms = NotOpen;
1147 m_alarmsText = lookup(NotOpen,s_alarms);
1148 m_span = -1;
1149 m_spanPos = -1;
1150 m_zapsig = -1;
1151 if (!valid())
1152 return;
1153 ::close(m_handle);
1154 m_handle = -1;
1155 if (m_type != Control && m_type != TypeUnknown)
1156 plugin.openClose(false);
1157 }
1158
1159 // Set data format. Fails if called for an interface
setFormat(Format format)1160 bool ZapDevice::setFormat(Format format)
1161 {
1162 if (m_type == DChan)
1163 return false;
1164 if (!ioctl(SetFormat,&format,0)) {
1165 Debug(m_owner,DebugNote,"%sFailed to set format '%s' on channel %u [%p]",
1166 m_name.safe(),lookup(format,s_formats,String((int)format)),
1167 m_channel,m_owner);
1168 return false;
1169 }
1170 DDebug(m_owner,DebugAll,"%sFormat set to '%s' on channel %u [%p]",
1171 m_name.safe(),lookup(format,s_formats),m_channel,m_owner);
1172 return true;
1173 }
1174
1175 // Set/unset tone detection
setDtmfDetect(bool detect)1176 bool ZapDevice::setDtmfDetect(bool detect)
1177 {
1178 int tmp = 0;
1179 #ifdef DAHDI_TONEDETECT
1180 setLinear(0,DebugAll);
1181 if (detect)
1182 tmp = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
1183 #endif
1184 if (!ioctl(SetToneDetect,&tmp,detect?DebugNote:DebugAll))
1185 return false;
1186 DDebug(m_owner,DebugAll,"%sTone detector %s on channel %u [%p]",
1187 m_name.safe(),detect?"started":"stopped",m_channel,m_owner);
1188 return true;
1189 }
1190
1191 // Update echo canceller (0: disable)
setEchoCancel(bool enable,unsigned int taps)1192 bool ZapDevice::setEchoCancel(bool enable, unsigned int taps)
1193 {
1194 enable = enable && taps;
1195 int tmp = 1;
1196 if (enable && (type() == E1 || type() == T1) &&
1197 !ioctl(SetAudioMode,&tmp,DebugMild))
1198 return false;
1199 if (!enable)
1200 taps = 0;
1201 if (!ioctl(SetEchoCancel,&taps,DebugMild))
1202 return false;
1203 if (taps)
1204 DDebug(m_owner,DebugAll,
1205 "%sEcho canceller enabled on channel %u (taps=%u) [%p]",
1206 m_name.safe(),m_channel,taps,m_owner);
1207 else
1208 DDebug(m_owner,DebugAll,"%sEcho canceller disabled on channel %u [%p]",
1209 m_name.safe(),m_channel,m_owner);
1210 return true;
1211 }
1212
1213 // Start echo training
startEchoTrain(unsigned int period)1214 bool ZapDevice::startEchoTrain(unsigned int period)
1215 {
1216 if (!period)
1217 return true;
1218 if (!ioctl(StartEchoTrain,&period,DebugNote))
1219 return false;
1220 DDebug(m_owner,DebugAll,"%sEcho train started for %u ms on channel %u [%p]",
1221 m_name.safe(),period,m_channel,m_owner);
1222 return true;
1223 }
1224
1225 // Poll for hook events (passive FXO)
pollHook()1226 void ZapDevice::pollHook()
1227 {
1228 if (m_rxHookSig < 0)
1229 return;
1230
1231 struct dahdi_params par;
1232 if (!ioctl(GetParams,&par))
1233 return;
1234
1235 int rxsig = par.rxhooksig;
1236 if (rxsig != RxSigOnHook)
1237 rxsig = RxSigOffHook;
1238 if (m_rxHookSig == rxsig)
1239 return;
1240 // state changed, save the event for later
1241 m_rxHookSig = rxsig;
1242 // states are reversed but that's how Zaptel is...
1243 m_savedEvent = (rxsig == RxSigOnHook) ? DAHDI_EVENT_WINKFLASH : DAHDI_EVENT_ONHOOK;
1244 }
1245
1246 // Send hook events
sendHook(HookEvent event)1247 bool ZapDevice::sendHook(HookEvent event)
1248 {
1249 const char* name = lookup(event,s_hookEvents);
1250 if (!name) {
1251 Debug(m_owner,DebugStub,"%sRequest to send unhandled hook event %u [%p]",
1252 m_name.safe(),event,this);
1253 return false;
1254 }
1255
1256 DDebug(m_owner,DebugAll,"%sSending hook event '%s' on channel %u [%p]",
1257 m_name.safe(),name,m_channel,m_owner);
1258 return ioctl(SetHook,&event);
1259 }
1260
1261 // Send DTMFs events using dialing or tone structure
1262 // dtmf: true - send DTMF (tone dialing), false - send MF (pulse dialing)
1263 // op: The dial operation to use
1264 // allDigits: true to send all digits at once
1265 // useTone: Used only if 'allDigits' is false and 'dtmf' is true
sendDtmf(const char * tone,bool dtmf,DialOperation op,bool allDigits,bool useTone)1266 bool ZapDevice::sendDtmf(const char* tone, bool dtmf, DialOperation op,
1267 bool allDigits, bool useTone)
1268 {
1269 XDebug(m_owner,DebugAll,"%ssendDtmf('%s',%u,%u,%u,%u) [%p]",
1270 m_name.safe(),tone,dtmf,op,allDigits,useTone,this);
1271 if (!(tone && *tone))
1272 return false;
1273
1274 struct dahdi_dialoperation dop;
1275 dop.op = op;
1276 dop.dialstr[0] = dtmf ? 'T' : 'P';
1277
1278 if (allDigits) {
1279 int len = strlen(tone);
1280 int maxLen = DAHDI_MAX_DTMF_BUF - 2;
1281 if (len > maxLen) {
1282 Debug(m_owner,DebugNote,
1283 "%sCan't send DTMF '%s' (len %d greater then max len %d) [%p]",
1284 m_name.safe(),tone,len,maxLen,this);
1285 return false;
1286 }
1287 strcpy(dop.dialstr+1,tone);
1288 DDebug(m_owner,DebugAll,"%sSending DTMF '%s' on channel %u [%p]",
1289 m_name.safe(),dop.dialstr,m_channel,this);
1290 return ioctl(ZapDevice::SetDial,&dop,DebugMild);
1291 }
1292
1293 if (useTone && dtmf)
1294 for (; *tone; tone++) {
1295 if (!sendDtmf(*tone))
1296 return false;
1297 }
1298 else {
1299 dop.dialstr[2] = 0;
1300 for (; *tone; tone++) {
1301 dop.dialstr[1] = *tone;
1302 DDebug(m_owner,DebugAll,"%sSending DTMF '%s' on channel %u [%p]",
1303 m_name.safe(),dop.dialstr,m_channel,this);
1304 if (!ioctl(ZapDevice::SetDial,&dop,DebugMild))
1305 return false;
1306 }
1307 }
1308 return true;
1309 }
1310
1311 // Send DTMF event using tone structure
sendDtmf(char tone)1312 bool ZapDevice::sendDtmf(char tone)
1313 {
1314 XDebug(m_owner,DebugAll,"%ssendDtmf('%c') [%p]",m_name.safe(),tone,this);
1315 #define YZAP_TONES 20
1316 static char tones[YZAP_TONES+1] = "0123456789*#ABCDabcd";
1317 static int zapTones[YZAP_TONES] = {
1318 DAHDI_TONE_DTMF_0, DAHDI_TONE_DTMF_1, DAHDI_TONE_DTMF_2, DAHDI_TONE_DTMF_3,
1319 DAHDI_TONE_DTMF_4, DAHDI_TONE_DTMF_5, DAHDI_TONE_DTMF_6, DAHDI_TONE_DTMF_7,
1320 DAHDI_TONE_DTMF_8, DAHDI_TONE_DTMF_9, DAHDI_TONE_DTMF_s, DAHDI_TONE_DTMF_p,
1321 DAHDI_TONE_DTMF_A, DAHDI_TONE_DTMF_B, DAHDI_TONE_DTMF_C, DAHDI_TONE_DTMF_D,
1322 DAHDI_TONE_DTMF_A, DAHDI_TONE_DTMF_B, DAHDI_TONE_DTMF_C, DAHDI_TONE_DTMF_D
1323 };
1324
1325 // Get zaptel tone
1326 int zapTone = 0;
1327 for (; zapTone < YZAP_TONES; zapTone++)
1328 if (tone == tones[zapTone])
1329 break;
1330 if (zapTone == YZAP_TONES) {
1331 Debug(m_owner,DebugNote,"%sCan't send invalid DTMF '%c' on channel %u [%p]",
1332 m_name.safe(),tone,m_channel,this);
1333 return false;
1334 }
1335 DDebug(m_owner,DebugAll,"%sSending DTMF '%c' (%d) on channel %u [%p]",
1336 m_name.safe(),tone,zapTones[zapTone],m_channel,this);
1337 return ioctl(ZapDevice::SendTone,&zapTones[zapTone],DebugMild);
1338 #undef YZAP_TONES
1339 }
1340
1341 // Get an event. Return 0 if no events. Set digit if the event is a DTMF/PULSE digit
getEvent(char & digit)1342 int ZapDevice::getEvent(char& digit)
1343 {
1344 int event = m_savedEvent;
1345 if (event)
1346 m_savedEvent = 0;
1347 else if (!ioctl(GetEvent,&event,DebugMild))
1348 return 0;
1349 if ((m_zapsig == DAHDI_SIG_EM) && (m_type == FXO)) {
1350 // For an "E&M FXO" the meanings of on/off hook change
1351 switch (event) {
1352 case OnHook:
1353 event = OffHookRing;
1354 break;
1355 case OffHookRing:
1356 event = RingBegin;
1357 break;
1358 }
1359 }
1360 if (event & DigitEvent) {
1361 digit = (char)event;
1362 event &= DigitEvent;
1363 XDebug(m_owner ,DebugAll,"%sGot digit event %d '%s'=%c on channel %u [%p]",
1364 m_name.safe(),event,lookup(event,s_events),digit,m_channel,m_owner);
1365 }
1366 #ifdef DEBUG
1367 else if (event)
1368 Debug(m_owner,DebugAll,"%sGot event %d on channel %u [%p]",
1369 m_name.safe(),event,m_channel,m_owner);
1370 #endif
1371 return event;
1372 }
1373
1374 // Get alarms from this device. Return true if alarms changed
checkAlarms()1375 bool ZapDevice::checkAlarms()
1376 {
1377 struct dahdi_spaninfo info;
1378 memset(&info,0,sizeof(info));
1379 info.spanno = m_span;
1380 if (!(ioctl(GetInfo,&info,DebugAll)))
1381 return false;
1382 if (m_alarms == info.alarms)
1383 return false;
1384 m_alarms = info.alarms;
1385 m_alarmsText = "";
1386 if (m_alarms) {
1387 for(int i = 0; s_alarms[i].token; i++)
1388 if (m_alarms & s_alarms[i].value) {
1389 m_alarmsText.append(s_alarms[i].token,",");
1390 if (s_alarms[i].value == ZapDevice::Yellow || s_alarms[i].value == ZapDevice::Blue) {
1391 bool notifStat = false;
1392 sendModuleUpdate("alarm",zapName(),notifStat,s_alarms[i].value);
1393 }
1394 }
1395 Debug(m_owner,DebugNote,"%sAlarms changed (%d,'%s') on channel %u [%p]",
1396 m_name.safe(),m_alarms,m_alarmsText.safe(),m_channel,m_owner);
1397 }
1398 return true;
1399 }
1400
1401 // Reset device's alarms
resetAlarms()1402 void ZapDevice::resetAlarms()
1403 {
1404 m_alarms = 0;
1405 m_alarmsText = "";
1406 Debug(m_owner,DebugInfo,"%sNo more alarms on channel %u [%p]",
1407 m_name.safe(),m_channel,m_owner);
1408 }
1409
1410 // Flush read/write buffers
flushBuffers(FlushTarget target)1411 bool ZapDevice::flushBuffers(FlushTarget target)
1412 {
1413 if (!ioctl(FlushBuffers,&target,DebugNote))
1414 return false;
1415 #ifdef DEBUG
1416 String tmp;
1417 if (target & FlushRead)
1418 tmp.append("read","/");
1419 if (target & FlushWrite)
1420 tmp.append("write","/");
1421 if (target & FlushEvent)
1422 tmp.append("events","/");
1423 DDebug(m_owner,DebugAll,"%sFlushed buffers (%s) on channel %u [%p]",
1424 m_name.safe(),tmp.c_str(),m_channel,m_owner);
1425 #endif
1426 return true;
1427 }
1428
1429 // Check if received data. Wait usec microseconds before returning
select(unsigned int usec)1430 bool ZapDevice::select(unsigned int usec)
1431 {
1432 FD_ZERO(&m_rdfds);
1433 FD_SET(m_handle, &m_rdfds);
1434 FD_ZERO(&m_errfds);
1435 FD_SET(m_handle, &m_errfds);
1436 m_tv.tv_sec = 0;
1437 m_tv.tv_usec = usec;
1438 int sel = ::select(m_handle+1,&m_rdfds,NULL,&m_errfds,&m_tv);
1439 if (sel >= 0) {
1440 m_event = FD_ISSET(m_handle,&m_errfds);
1441 m_canRead = FD_ISSET(m_handle,&m_rdfds);
1442 m_selectError = false;
1443 return true;
1444 }
1445 if (!(canRetry() || m_selectError)) {
1446 Debug(m_owner,DebugWarn,"%sSelect failed on channel %u. %d: %s [%p]",
1447 m_name.safe(),m_channel,errno,::strerror(errno),m_owner);
1448 m_selectError = true;
1449 }
1450 return false;
1451 }
1452
recv(void * buffer,int len)1453 int ZapDevice::recv(void* buffer, int len)
1454 {
1455 errno = 0;
1456 int r = ::read(m_handle,buffer,len);
1457 if (r >= 0) {
1458 m_event = false;
1459 m_readError = false;
1460 return r;
1461 }
1462 // The caller should check for events if the error is ELAST
1463 m_event = (errno == ELAST);
1464 if (m_event)
1465 return -1;
1466 if (!(canRetry() || m_readError)) {
1467 Debug(m_owner,DebugWarn,"%sRead failed on channel %u. %d: %s [%p]",
1468 m_name.safe(),m_channel,errno,::strerror(errno),m_owner);
1469 m_readError = true;
1470 }
1471 return -1;
1472 }
1473
send(const void * buffer,int len)1474 int ZapDevice::send(const void* buffer, int len)
1475 {
1476 errno = 0;
1477 int w = ::write(m_handle,buffer,len);
1478 if (w == len) {
1479 m_writeError = false;
1480 return w;
1481 }
1482 if (errno == ELAST)
1483 m_event = true;
1484 else if (!m_writeError) {
1485 Debug(m_owner,DebugWarn,
1486 "%sWrite failed on channel %u (sent %d instead of %d). %d: %s [%p]",
1487 m_name.safe(),m_channel,w>=0?w:0,len,errno,::strerror(errno),m_owner);
1488 m_writeError = true;
1489 }
1490 return (w < 0 ? -1 : w);
1491 }
1492
1493 // Get driver version and echo canceller
getVersion(NamedList & dest)1494 bool ZapDevice::getVersion(NamedList& dest)
1495 {
1496 struct dahdi_versioninfo info;
1497 if (!ioctl(GetVersion,&info,DebugNote))
1498 return false;
1499 dest.setParam("version",info.version);
1500 dest.setParam("echocanceller",info.echo_canceller);
1501 return true;
1502 }
1503
1504 // Get span info
getSpanInfo(int span,NamedList & dest,int * spans)1505 bool ZapDevice::getSpanInfo(int span, NamedList& dest, int* spans)
1506 {
1507 struct dahdi_spaninfo info;
1508 memset(&info,0,sizeof(info));
1509 info.spanno = (span != -1) ? span : m_span;
1510 if (!ioctl(GetInfo,&info,DebugNote))
1511 return false;
1512 dest.addParam("span",String(span));
1513 dest.addParam("name",info.name);
1514 dest.addParam("desc",info.desc);
1515 dest.addParam("alarms",String(info.alarms));
1516 String alarmsText;
1517 for(int i = 0; s_alarms[i].token; i++)
1518 if (info.alarms & s_alarms[i].value)
1519 alarmsText.append(s_alarms[i].token,",");
1520 dest.addParam("alarmstext",alarmsText);
1521 dest.addParam("configured-chans",String(info.numchans));
1522 dest.addParam("total-chans",String(info.totalchans));
1523 if (spans)
1524 *spans = info.totalspans;
1525 return true;
1526 }
1527
1528 // Get channel parameters
getChanParams(NamedList & dest)1529 bool ZapDevice::getChanParams(NamedList& dest)
1530 {
1531 struct dahdi_params par;
1532 if (!ioctl(GetParams,&par))
1533 return false;
1534 dest.addParam("format",lookup(par.curlaw,s_formats));
1535 dest.addParam("prewinktime",String(par.prewinktime));
1536 dest.addParam("preflashtime",String(par.preflashtime));
1537 dest.addParam("winktime",String(par.winktime));
1538 dest.addParam("flashtime",String(par.flashtime));
1539 dest.addParam("starttime",String(par.starttime));
1540 dest.addParam("rxwinktime",String(par.rxwinktime));
1541 dest.addParam("rxflashtime",String(par.rxflashtime));
1542 dest.addParam("debouncetime",String(par.debouncetime));
1543 dest.addParam("pulsebreaktime",String(par.pulsebreaktime));
1544 dest.addParam("pulsemaketime",String(par.pulsemaketime));
1545 dest.addParam("pulseaftertime",String(par.pulseaftertime));
1546 return true;
1547 }
1548
1549 // Set/get dial parameters (DTMF/MF length)
dialParams(bool set,int & toneLen,int & mfLen)1550 bool ZapDevice::dialParams(bool set, int& toneLen, int& mfLen)
1551 {
1552 struct dahdi_dialparams dp;
1553 ::memset(&dp,0,sizeof(struct dahdi_dialparams));
1554
1555 if (!set) {
1556 if (!ioctl(GetDialParams,&dp,DebugMild))
1557 return false;
1558 toneLen = dp.dtmf_tonelen;
1559 mfLen = dp.mfv1_tonelen;
1560 return true;
1561 }
1562
1563 dp.dtmf_tonelen = toneLen;
1564 dp.mfv1_tonelen = mfLen;
1565 return ioctl(SetDialParams,&dp,DebugNote);
1566 }
1567
1568 // Make IOCTL requests on this device
ioctl(IoctlRequest request,void * param,int level)1569 bool ZapDevice::ioctl(IoctlRequest request, void* param, int level)
1570 {
1571 if (!param) {
1572 Debug(&plugin,DebugStub,"ZapDevice::ioctl(). 'param' is missing");
1573 return false;
1574 }
1575
1576 int ret = -1;
1577 switch (request) {
1578 case GetEvent:
1579 ret = ::ioctl(m_handle,DAHDI_GETEVENT,param);
1580 break;
1581 case SetChannel:
1582 ret = ::ioctl(m_handle,DAHDI_SPECIFY,param);
1583 break;
1584 case SetBlkSize:
1585 ret = ::ioctl(m_handle,DAHDI_SET_BLOCKSIZE,param);
1586 break;
1587 case SetBuffers:
1588 ret = ::ioctl(m_handle,DAHDI_SET_BUFINFO,param);
1589 break;
1590 case SetFormat:
1591 ret = ::ioctl(m_handle,DAHDI_SETLAW,param);
1592 break;
1593 case SetAudioMode:
1594 ret = ::ioctl(m_handle,DAHDI_AUDIOMODE,param);
1595 break;
1596 case SetEchoCancel:
1597 ret = ::ioctl(m_handle,DAHDI_ECHOCANCEL,param);
1598 break;
1599 case SetDial:
1600 ret = ::ioctl(m_handle,DAHDI_DIAL,param);
1601 break;
1602 case SetHook:
1603 ret = ::ioctl(m_handle,DAHDI_HOOK,param);
1604 break;
1605 case SetToneDetect:
1606 #ifdef DAHDI_TONEDETECT
1607 ret = ::ioctl(m_handle,DAHDI_TONEDETECT,param);
1608 break;
1609 #else
1610 // Show message only if requested to set tone detection
1611 if (param && *param)
1612 Debug(m_owner,level,"%sIOCTL(%s) failed: unsupported request [%p]",
1613 m_name.safe(),lookup(SetToneDetect,s_ioctl_request),m_owner);
1614 return false;
1615 #endif
1616 case SetPolarity:
1617 ret = ::ioctl(m_handle,DAHDI_SETPOLARITY,param);
1618 break;
1619 case SetLinear:
1620 ret = ::ioctl(m_handle,DAHDI_SETLINEAR,param);
1621 break;
1622 case SetDialParams:
1623 ret = ::ioctl(m_handle,DAHDI_SET_DIALPARAMS,param);
1624 break;
1625 case GetParams:
1626 ret = ::ioctl(m_handle,DAHDI_GET_PARAMS,param);
1627 break;
1628 case GetInfo:
1629 ret = ::ioctl(m_handle,DAHDI_SPANSTAT,param);
1630 break;
1631 case GetDialParams:
1632 ret = ::ioctl(m_handle,DAHDI_GET_DIALPARAMS,param);
1633 break;
1634 case StartEchoTrain:
1635 ret = ::ioctl(m_handle,DAHDI_ECHOTRAIN,param);
1636 break;
1637 case FlushBuffers:
1638 ret = ::ioctl(m_handle,DAHDI_FLUSH,param);
1639 break;
1640 case SendTone:
1641 ret = ::ioctl(m_handle,DAHDI_SENDTONE,param);
1642 break;
1643 case GetVersion:
1644 ret = ::ioctl(m_handle,DAHDI_GETVERSION,param);
1645 break;
1646 }
1647 if (!ret || errno == EINPROGRESS) {
1648 if (errno == EINPROGRESS)
1649 DDebug(m_owner,DebugAll,"%sIOCTL(%s) in progress on channel %u (param=%d) [%p]",
1650 m_name.safe(),lookup(request,s_ioctl_request),
1651 m_channel,*(int*)param,m_owner);
1652 #ifdef XDEBUG
1653 else if (request != GetEvent)
1654 Debug(m_owner,DebugAll,"%sIOCTL(%s) succedded on channel %u (param=%d) [%p]",
1655 m_name.safe(),lookup(request,s_ioctl_request),
1656 m_channel,*(int*)param,m_owner);
1657 #endif
1658 return true;
1659 }
1660 Debug(m_owner,level,"%sIOCTL(%s) failed on channel %u (param=%d). %d: %s [%p]",
1661 m_name.safe(),lookup(request,s_ioctl_request),
1662 m_channel,*(int*)param,errno,::strerror(errno),m_owner);
1663 return false;
1664 }
1665
1666
1667 /**
1668 * ZapInterface
1669 */
ZapInterface(const NamedList & params)1670 ZapInterface::ZapInterface(const NamedList& params)
1671 : SignallingComponent(params,¶ms,"tdm"),
1672 m_device(ZapDevice::DChan,this,0,0),
1673 m_priority(Thread::Normal),
1674 m_errorMask(255),
1675 m_numbufs(16), m_bufsize(1024), m_buffer(0),
1676 m_readOnly(false), m_sendReadOnly(false),
1677 m_notify(0),
1678 m_timerRxUnder(0)
1679 {
1680 m_buffer = new unsigned char[m_bufsize + ZAP_CRC_LEN];
1681 XDebug(this,DebugAll,"ZapInterface::ZapInterface() [%p]",this);
1682 }
1683
~ZapInterface()1684 ZapInterface::~ZapInterface()
1685 {
1686 cleanup(false);
1687 delete[] m_buffer;
1688 XDebug(this,DebugAll,"ZapInterface::~ZapInterface() [%p]",this);
1689 }
1690
1691 // Called by the factory to create Zaptel interfaces or spans
create(const String & type,NamedList & name)1692 SignallingComponent* ZapInterface::create(const String& type, NamedList& name)
1693 {
1694 bool circuit = true;
1695 if (type == "SignallingInterface")
1696 circuit = false;
1697 else if (type == "SignallingCircuitSpan")
1698 ;
1699 else
1700 return 0;
1701
1702 TempObjectCounter cnt(plugin.objectsCounter());
1703 const String* module = name.getParam("module");
1704 if (module && *module != "zapcard")
1705 return 0;
1706 Configuration cfg(Engine::configFile("zapcard"));
1707 const char* sectName = name.getValue((circuit ? "voice" : "sig"),name.getValue("basename",name));
1708 NamedList* config = cfg.getSection(sectName);
1709
1710 if (!name.getBoolValue(YSTRING("local-config"),false))
1711 config = &name;
1712 else if (!config) {
1713 DDebug(&plugin,DebugConf,"No section '%s' in configuration",c_safe(sectName));
1714 return 0;
1715 } else
1716 name.copyParams(*config);
1717
1718 #ifdef DEBUG
1719 if (plugin.debugAt(DebugAll)) {
1720 String tmp;
1721 name.dump(tmp,"\r\n ",'\'',true);
1722 Debug(&plugin,DebugAll,"ZapInterface::create %s%s",
1723 (circuit ? "span" : "interface"),tmp.c_str());
1724 }
1725 #endif
1726 String sDevType = config->getValue("type");
1727 ZapDevice::Type devType = (ZapDevice::Type)lookup(sDevType,s_types,ZapDevice::E1);
1728
1729 NamedList dummy("general");
1730 NamedList* general = cfg.getSection("general");
1731 if (!general)
1732 general = &dummy;
1733
1734 String sOffset = config->getValue("offset");
1735 unsigned int offset = (unsigned int)sOffset.toInteger(-1);
1736 if (offset == (unsigned int)-1) {
1737 Debug(&plugin,DebugWarn,"Section '%s'. Invalid offset='%s'",
1738 config->c_str(),sOffset.safe());
1739 return 0;
1740 }
1741
1742 if (circuit) {
1743 ZapSpan* span = new ZapSpan(name);
1744 bool ok = false;
1745 if (span->group())
1746 ok = span->init(devType,offset,*config,*general,name);
1747 else
1748 Debug(&plugin,DebugWarn,"Can't create span '%s'. Group is missing",
1749 span->id().safe());
1750 if (ok)
1751 return span;
1752 TelEngine::destruct(span);
1753 return 0;
1754 }
1755
1756 // Check span type
1757 if (devType != ZapDevice::E1 && devType != ZapDevice::T1 && devType != ZapDevice::BRI) {
1758 Debug(&plugin,DebugWarn,"Section '%s'. Can't create D-channel for type='%s'",
1759 config->c_str(),sDevType.c_str());
1760 return 0;
1761 }
1762 // Check channel
1763 String sig = config->getValue("sigchan");
1764 unsigned int count = (devType == ZapDevice::E1 ? 31 : 24);
1765 if (sig.null()) {
1766 switch (devType) {
1767 case ZapDevice::E1:
1768 sig = 16;
1769 break;
1770 case ZapDevice::T1:
1771 sig = 24;
1772 break;
1773 case ZapDevice::BRI:
1774 sig = 3;
1775 break;
1776 default:
1777 break;
1778 }
1779 }
1780 unsigned int code = (unsigned int)sig.toInteger(0);
1781 if (!(sig && code && code <= count)) {
1782 Debug(&plugin,DebugWarn,"Section '%s'. Invalid sigchan='%s' for type='%s'",
1783 config->c_str(),sig.safe(),sDevType.c_str());
1784 return 0;
1785 }
1786 ZapInterface* iface = new ZapInterface(name);
1787 if (iface->init(devType,code,offset+code,*config,*general,name))
1788 return iface;
1789 TelEngine::destruct(iface);
1790 return 0;
1791 }
1792
init(ZapDevice::Type type,unsigned int code,unsigned int channel,const NamedList & config,const NamedList & defaults,const NamedList & params)1793 bool ZapInterface::init(ZapDevice::Type type, unsigned int code, unsigned int channel,
1794 const NamedList& config, const NamedList& defaults, const NamedList& params)
1795 {
1796 TempObjectCounter cnt(plugin.objectsCounter());
1797 m_device.channel(channel,code);
1798 m_readOnly = getBoolValue("readonly",config,defaults,params);
1799 m_priority = Thread::priority(config.getValue("priority",defaults.getValue("priority")));
1800 int rx = params.getIntValue("rxunderrun");
1801 if (rx > 0)
1802 m_timerRxUnder.interval(rx);
1803 int i = params.getIntValue("errormask",config.getIntValue("errormask",255));
1804 m_errorMask = ((i >= 0 && i < 256) ? i : 255);
1805 if (debugAt(DebugInfo)) {
1806 String s;
1807 s << "driver=" << plugin.debugName();
1808 s << " section=" << config.c_str();
1809 s << " type=" << lookup(type,s_types);
1810 s << " channel=" << channel;
1811 s << " errormask=" << (unsigned int)m_errorMask;
1812 s << " readonly=" << String::boolText(m_readOnly);
1813 s << " rxunderruninterval=" << (unsigned int)m_timerRxUnder.interval() << " ms";
1814 s << " numbufs=" << (unsigned int)m_numbufs;
1815 s << " bufsize=" << (unsigned int)m_bufsize;
1816 s << " priority=" << Thread::priority(m_priority);
1817 Debug(this,DebugInfo,"D-channel: %s [%p]",s.c_str(),this);
1818 }
1819 m_down = false;
1820 return true;
1821 }
1822
1823 // Process incoming data
process()1824 bool ZapInterface::process()
1825 {
1826 if (!m_device.select(100))
1827 return false;
1828 if (!m_device.canRead()) {
1829 if (m_device.event())
1830 checkEvents();
1831 return false;
1832 }
1833
1834 int r = m_device.recv(m_buffer,m_bufsize + ZAP_CRC_LEN);
1835 if (r == -1) {
1836 if (m_device.event())
1837 checkEvents();
1838 return false;
1839 }
1840 if (r < ZAP_CRC_LEN + 1) {
1841 Debug(this,DebugMild,"Short read %u bytes (with CRC) [%p]",r,this);
1842 return false;
1843 }
1844
1845 s_ifaceNotifyMutex.lock();
1846 m_notify = 0;
1847 s_ifaceNotifyMutex.unlock();
1848 DataBlock packet(m_buffer,r - ZAP_CRC_LEN,false);
1849 #ifdef XDEBUG
1850 String hex;
1851 hex.hexify(packet.data(),packet.length(),' ');
1852 Debug(this,DebugAll,"Received data: %s [%p]",hex.safe(),this);
1853 #endif
1854 receivedPacket(packet);
1855 packet.clear(false);
1856 return true;
1857 }
1858
getObject(const String & name) const1859 void* ZapInterface::getObject(const String& name) const
1860 {
1861 if (name == "ZapInterface")
1862 return (void*)this;
1863 return SignallingInterface::getObject(name);
1864 }
1865
1866 // Send signalling packet
transmitPacket(const DataBlock & packet,bool repeat,PacketType type)1867 bool ZapInterface::transmitPacket(const DataBlock& packet, bool repeat, PacketType type)
1868 {
1869 static DataBlock crc(0,ZAP_CRC_LEN);
1870
1871 if (m_readOnly) {
1872 if (!m_sendReadOnly)
1873 Debug(this,DebugWarn,"Attempt to send data on read only interface");
1874 m_sendReadOnly = true;
1875 return false;
1876 }
1877 if (!m_device.valid())
1878 return false;
1879
1880 #ifdef XDEBUG
1881 String hex;
1882 hex.hexify(packet.data(),packet.length(),' ');
1883 Debug(this,DebugAll,"Sending data: %s [%p]",hex.safe(),this);
1884 #endif
1885 DataBlock pkt(packet);
1886 // zaptel needs the extra space to write the CRC there
1887 pkt += crc;
1888 return m_device.send(pkt.data(),pkt.length());
1889 }
1890
1891 // Interface control. Open device and start worker when enabled, cleanup when disabled
control(Operation oper,NamedList * params)1892 bool ZapInterface::control(Operation oper, NamedList* params)
1893 {
1894 DDebug(this,DebugAll,"Control with oper=%u [%p]",oper,this);
1895 switch (oper) {
1896 case Enable:
1897 case Disable:
1898 break;
1899 case EnableTx:
1900 case DisableTx:
1901 if (m_readOnly == (oper == DisableTx))
1902 return TelEngine::controlReturn(params,true);
1903 m_readOnly = (oper == DisableTx);
1904 m_sendReadOnly = false;
1905 Debug(this,DebugInfo,"Tx is %sabled [%p]",m_readOnly?"dis":"en",this);
1906 return TelEngine::controlReturn(params,true);
1907 case Query:
1908 return TelEngine::controlReturn(params,valid());
1909 default:
1910 return SignallingInterface::control(oper,params);
1911 }
1912 if (oper == Enable) {
1913 if (valid())
1914 return TelEngine::controlReturn(params,true);
1915 bool ok = m_device.valid() || m_device.open(m_numbufs,m_bufsize);
1916 if (ok)
1917 ok = ZapWorkerClient::start(m_priority,this,debugName());
1918 if (ok) {
1919 Debug(this,DebugAll,"Enabled [%p]",this);
1920 m_timerRxUnder.start();
1921 }
1922 else {
1923 Debug(this,DebugWarn,"Enable failed [%p]",this);
1924 control(Disable,0);
1925 }
1926 return TelEngine::controlReturn(params,ok);
1927 }
1928 // oper is Disable
1929 bool ok = valid();
1930 m_timerRxUnder.stop();
1931 ZapWorkerClient::stop();
1932 m_device.close();
1933 if (ok)
1934 Debug(this,DebugAll,"Disabled [%p]",this);
1935 return TelEngine::controlReturn(params,true);
1936 }
1937
1938 // Check if received any data in the last interval. Notify receiver
timerTick(const Time & when)1939 void ZapInterface::timerTick(const Time& when)
1940 {
1941 if (!m_timerRxUnder.timeout(when.msec()))
1942 return;
1943 s_ifaceNotifyMutex.lock();
1944 if (m_notify) {
1945 if (m_notify == 1) {
1946 DDebug(this,DebugMild,"RX idle for " FMT64 "ms. Notifying receiver [%p]",
1947 m_timerRxUnder.interval(),this);
1948 notify(RxUnderrun);
1949 m_notify = 2;
1950 }
1951 }
1952 else
1953 m_notify = 1;
1954 s_ifaceNotifyMutex.unlock();
1955 m_timerRxUnder.start(when.msec());
1956 }
1957
checkEvents()1958 void ZapInterface::checkEvents()
1959 {
1960 char c = 0;
1961 int event = m_device.getEvent(c);
1962 if (!event)
1963 return;
1964 int level = DebugWarn;
1965 switch (event) {
1966 case ZapDevice::Alarm:
1967 case ZapDevice::NoAlarm:
1968 if (event == ZapDevice::Alarm) {
1969 m_device.checkAlarms();
1970 Debug(this,DebugNote,"Alarms changed '%s' [%p]",
1971 m_device.alarmsText().safe(),this);
1972 notify(LinkDown);
1973 sendModuleUpdate("interfaceDown",m_device.zapName(),m_down,LinkDown);
1974 }
1975 else {
1976 m_device.resetAlarms();
1977 DDebug(this,DebugInfo,"No more alarms [%p]",this);
1978 notify(LinkUp);
1979 sendModuleUpdate("interfaceUp",m_device.zapName(),m_down,LinkUp);
1980 }
1981 return;
1982 case ZapDevice::HdlcAbort:
1983 if (m_errorMask & ZAP_ERR_ABORT)
1984 notify(AlignError);
1985 break;
1986 case ZapDevice::HdlcOverrun:
1987 if (m_errorMask & ZAP_ERR_OVERRUN)
1988 notify(RxOverflow);
1989 break;
1990 case ZapDevice::PulseDigit:
1991 case ZapDevice::DtmfDown:
1992 case ZapDevice::DtmfUp:
1993 Debug(this,DebugNote,"Got DTMF event '%s' on D-channel [%p]",
1994 lookup(event,s_events,""),this);
1995 return;
1996 default:
1997 level = DebugStub;
1998 }
1999 DDebug(this,level,"Got event %d ('%s') [%p]",event,lookup(event,s_events,""),this);
2000 }
2001
2002
2003 /**
2004 * ZapSpan
2005 */
2006 // Create circuits
init(ZapDevice::Type type,unsigned int offset,const NamedList & config,const NamedList & defaults,const NamedList & params)2007 bool ZapSpan::init(ZapDevice::Type type, unsigned int offset,
2008 const NamedList& config, const NamedList& defaults, const NamedList& params)
2009 {
2010 TempObjectCounter cnt(plugin.objectsCounter());
2011 String voice = config.getValue("voicechans");
2012 unsigned int chans = 0;
2013 bool digital = true;
2014 switch (type) {
2015 case ZapDevice::E1:
2016 if (!voice)
2017 voice = "1-15.17-31";
2018 chans = 31;
2019 m_increment = 32;
2020 break;
2021 case ZapDevice::T1:
2022 if (!voice)
2023 voice = "1-23";
2024 chans = 24;
2025 m_increment = 24;
2026 break;
2027 case ZapDevice::BRI:
2028 if (!voice)
2029 voice = "1-2";
2030 chans = 3;
2031 m_increment = 3;
2032 break;
2033 case ZapDevice::FXO:
2034 case ZapDevice::FXS:
2035 digital = false;
2036 if (!voice)
2037 voice = "1";
2038 chans = (unsigned int)-1;
2039 break;
2040 default:
2041 Debug(m_group,DebugStub,
2042 "ZapSpan('%s'). Can't create circuits for type=%s [%p]",
2043 id().safe(),lookup(type,s_types),this);
2044 return false;
2045 }
2046 unsigned int count = 0;
2047 unsigned int* cics = SignallingUtils::parseUIntArray(voice,1,chans,count,true);
2048 if (!cics) {
2049 Debug(m_group,DebugWarn,
2050 "ZapSpan('%s'). Invalid voicechans='%s' (type=%s,chans=%u) [%p]",
2051 id().safe(),voice.safe(),lookup(type,s_types),chans,this);
2052 return false;
2053 }
2054
2055 if (!digital)
2056 m_increment = chans = count;
2057 m_increment = config.getIntValue("increment",m_increment);
2058 unsigned int start = config.getIntValue("start",params.getIntValue("start",0));
2059
2060 // Create and insert circuits
2061 unsigned int added = 0;
2062 DDebug(m_group,DebugAll,
2063 "ZapSpan('%s'). Creating circuits starting with %u [%p]",
2064 id().safe(),start,this);
2065 for (unsigned int i = 0; i < count; i++) {
2066 unsigned int code = start + cics[i];
2067 unsigned int channel = offset + cics[i];
2068 ZapCircuit* cic = 0;
2069 DDebug(m_group,DebugAll,
2070 "ZapSpan('%s'). Creating circuit code=%u channel=%u [%p]",
2071 id().safe(),code,channel,this);
2072 if (digital)
2073 cic = new ZapCircuit(type,code,channel,this,config,defaults,params);
2074 else
2075 cic = new ZapAnalogCircuit(type,code,channel,this,config,defaults,params);
2076 if (m_group->insert(cic)) {
2077 added++;
2078 continue;
2079 }
2080 TelEngine::destruct(cic);
2081 Debug(m_group,DebugConf,
2082 "ZapSpan('%s'). Duplicate circuit code=%u (channel=%u) [%p]",
2083 id().safe(),code,channel,this);
2084 }
2085 if (!added) {
2086 Debug(m_group,DebugWarn,"ZapSpan('%s'). No circuits inserted for this span [%p]",
2087 id().safe(),this);
2088 delete[] cics;
2089 return false;
2090 }
2091
2092 if (m_group && m_group->debugAt(DebugInfo)) {
2093 String s;
2094 s << "driver=" << plugin.debugName();
2095 s << " section=" << config.c_str();
2096 s << " type=" << lookup(type,s_types);
2097 String c,ch;
2098 for (unsigned int i = 0; i < count; i++) {
2099 c.append(String(start+cics[i]),",");
2100 ch.append(String(offset+cics[i]),",");
2101 }
2102 s << " channels=" << ch;
2103 s << " circuits=" << c;
2104 Debug(m_group,DebugInfo,"ZapSpan('%s') %s [%p]",id().safe(),s.c_str(),this);
2105 }
2106 delete[] cics;
2107 return true;
2108 }
2109
2110
2111 /**
2112 * ZapCircuit
2113 */
ZapCircuit(ZapDevice::Type type,unsigned int code,unsigned int channel,ZapSpan * span,const NamedList & config,const NamedList & defaults,const NamedList & params)2114 ZapCircuit::ZapCircuit(ZapDevice::Type type, unsigned int code, unsigned int channel,
2115 ZapSpan* span, const NamedList& config, const NamedList& defaults,
2116 const NamedList& params)
2117 : SignallingCircuit(TDM,code,Idle,span->group(),span),
2118 m_device(type,span->group(),channel,code),
2119 m_format(ZapDevice::Alaw),
2120 m_echoCancel(false),
2121 m_crtEchoCancel(false),
2122 m_echoTaps(0),
2123 m_echoTrain(400),
2124 m_dtmfDetect(false),
2125 m_crtDtmfDetect(false),
2126 m_canSend(true),
2127 m_idleValue(255),
2128 m_priority(Thread::Normal),
2129 m_source(0),
2130 m_consumer(0),
2131 m_buflen(0),
2132 m_consBufMax(0),
2133 m_consErrors(0),
2134 m_consErrorBytes(0),
2135 m_consTotal(0),
2136 m_errno(0)
2137 {
2138 m_dtmfDetect = config.getBoolValue("dtmfdetect",true);
2139 if (m_dtmfDetect && ZapDevice::SetToneDetect > 100) {
2140 Debug(group(),DebugWarn,
2141 "ZapCircuit(%u). DTMF detection is not supported by hardware [%p]",
2142 code,this);
2143 m_dtmfDetect = false;
2144 }
2145 m_crtDtmfDetect = m_dtmfDetect;
2146 int tmp = config.getIntValue("echotaps",defaults.getIntValue("echotaps",0));
2147 m_echoTaps = tmp >= 0 ? tmp : 0;
2148 m_crtEchoCancel = m_echoCancel = m_echoTaps;
2149 tmp = (unsigned int)config.getIntValue("echotrain",defaults.getIntValue("echotrain",400));
2150 m_echoTrain = tmp >= 0 ? tmp : 0;
2151 m_canSend = !getBoolValue("readonly",config,defaults,params);
2152 m_buflen = (unsigned int)config.getIntValue("buflen",defaults.getIntValue("buflen",160));
2153 if (!m_buflen)
2154 m_buflen = 160;
2155 m_consBufMax = m_buflen * 4;
2156 m_sourceBuffer.assign(0,m_buflen);
2157 m_idleValue = defaults.getIntValue("idlevalue",0xff);
2158 m_idleValue = params.getIntValue("idlevalue",config.getIntValue("idlevalue",m_idleValue));
2159 m_priority = Thread::priority(config.getValue("priority",defaults.getValue("priority")));
2160
2161 switch (type) {
2162 case ZapDevice::E1:
2163 case ZapDevice::BRI:
2164 m_format = ZapDevice::Alaw;
2165 break;
2166 case ZapDevice::T1:
2167 m_format = ZapDevice::Mulaw;
2168 break;
2169 case ZapDevice::FXO:
2170 if (getBoolValue("trackhook",config,defaults,params)) {
2171 if (m_canSend)
2172 Debug(group(),DebugNote,"ZapCircuit(%u): Hook tracking for active FXO [%p]",code,this);
2173 m_device.initHook();
2174 }
2175 // fall through
2176 case ZapDevice::FXS:
2177 {
2178 const char* f = config.getValue("format",defaults.getValue("format"));
2179 m_format = (ZapDevice::Format)lookup(f,s_formats,ZapDevice::Mulaw);
2180 if (m_format != ZapDevice::Alaw && m_format != ZapDevice::Mulaw)
2181 m_format = ZapDevice::Mulaw;
2182 }
2183 break;
2184 default:
2185 Debug(group(),DebugStub,"ZapCircuit(%u). Unhandled circuit type=%d [%p]",
2186 code,type,this);
2187 }
2188
2189 if (group() && group()->debugAt(DebugAll)) {
2190 String s;
2191 s << "driver=" << plugin.debugName();
2192 s << " type=" << lookup(type,s_types);
2193 s << " channel=" << channel;
2194 s << " cic=" << code;
2195 s << " dtmfdetect=" << String::boolText(m_dtmfDetect);
2196 s << " echotaps=" << m_echoTaps;
2197 s << " echotrain=" << m_echoTrain;
2198 s << " buflen=" << m_buflen;
2199 s << " readonly=" << String::boolText(!m_canSend);
2200 s << " idlevalue=" << (unsigned int)m_idleValue;
2201 s << " priority=" << Thread::priority(m_priority);
2202 Debug(group(),DebugAll,"ZapCircuit %s [%p]",s.c_str(),this);
2203 }
2204 }
2205
2206 // Change circuit status. Clear events on status change
2207 // New status is Connect: Open device. Create source/consumer. Start worker
2208 // Cleanup on disconnect
status(Status newStat,bool sync)2209 bool ZapCircuit::status(Status newStat, bool sync)
2210 {
2211 if (SignallingCircuit::status() == newStat)
2212 return true;
2213 if (SignallingCircuit::status() == Missing) {
2214 Debug(group(),DebugNote,
2215 "ZapCircuit(%u). Can't change status to '%s'. Circuit is missing [%p]",
2216 code(),lookupStatus(newStat),this);
2217 return false;
2218 }
2219 TempObjectCounter cnt(plugin.objectsCounter());
2220 Status oldStat = SignallingCircuit::status();
2221 // Allow status change for the following values
2222 switch (newStat) {
2223 case Missing:
2224 case Disabled:
2225 case Idle:
2226 case Reserved:
2227 case Connected:
2228 if (!SignallingCircuit::status(newStat,sync))
2229 return false;
2230 clearEvents();
2231 if (!Engine::exiting())
2232 DDebug(group(),DebugAll,"ZapCircuit(%u). Changed status to '%s' [%p]",
2233 code(),lookupStatus(newStat),this);
2234 if (newStat == Connected)
2235 break;
2236 if (oldStat == Connected)
2237 cleanup(false,newStat);
2238 return true;
2239 default: ;
2240 Debug(group(),DebugStub,
2241 "ZapCircuit(%u). Can't change status to unhandled value %u [%p]",
2242 code(),newStat,this);
2243 return false;
2244 }
2245 // Connected: open device, create source/consumer, start worker
2246 while (true) {
2247 if (!m_device.open(0,m_buflen))
2248 break;
2249 m_device.flushBuffers();
2250 setFormat(m_format);
2251 createData();
2252 String addr;
2253 if (group())
2254 addr << group()->debugName() << "/";
2255 addr << code();
2256 if (!ZapWorkerClient::start(m_priority,group(),addr))
2257 break;
2258 return true;
2259 }
2260 // Rollback on error
2261 cleanup(false,oldStat);
2262 return false;
2263 }
2264
2265 // Update data format for zaptel device and source/consumer
updateFormat(const char * format,int direction)2266 bool ZapCircuit::updateFormat(const char* format, int direction)
2267 {
2268 s_sourceAccessMutex.lock();
2269 RefPointer<ZapSource> src = m_source;
2270 s_sourceAccessMutex.unlock();
2271
2272 if (!(src && format && *format))
2273 return false;
2274 // Do nothing if format is the same
2275 if (src->getFormat() == format && m_consumer && m_consumer->getFormat() == format)
2276 return false;
2277 TempObjectCounter cnt(plugin.objectsCounter());
2278 // Check format
2279 // T1,E1: allow alaw or mulaw
2280 int f = lookup(format,s_formats,-2);
2281 switch (m_device.type()) {
2282 case ZapDevice::E1:
2283 case ZapDevice::T1:
2284 case ZapDevice::BRI:
2285 case ZapDevice::FXS:
2286 case ZapDevice::FXO:
2287 if (f == ZapDevice::Alaw || f == ZapDevice::Mulaw)
2288 break;
2289 // Fallthrough to deny format change
2290 default:
2291 Debug(group(),DebugNote,
2292 "ZapCircuit(%u). Can't set format to '%s' for type=%s [%p]",
2293 code(),format,lookup(m_device.type(),s_types),this);
2294 return false;
2295 }
2296 // Update the format for Zaptel device
2297 if (setFormat((ZapDevice::Format)f)) {
2298 src->changeFormat(format);
2299 if (m_consumer)
2300 m_consumer->changeFormat(format);
2301 return true;
2302 }
2303 Debug(group(),DebugNote,
2304 "ZapCircuit(%u). Failed to update data format to '%s' [%p]",
2305 code(),format,this);
2306 return false;
2307 }
2308
2309 // Setup echo canceller or start echo canceller training
setParam(const String & param,const String & value)2310 bool ZapCircuit::setParam(const String& param, const String& value)
2311 {
2312 TempObjectCounter cnt(plugin.objectsCounter());
2313 if (param == "echotrain") {
2314 int tmp = value.toInteger(-1);
2315 if (tmp >= 0)
2316 m_echoTrain = tmp;
2317 return m_device.valid() && m_crtEchoCancel && m_device.startEchoTrain(m_echoTrain);
2318 }
2319 if (param == "echocancel") {
2320 if (!value.isBoolean())
2321 return false;
2322 bool tmp = value.toBoolean();
2323 if (tmp == m_crtEchoCancel)
2324 return true;
2325 if (m_echoTaps)
2326 m_crtEchoCancel = tmp;
2327 else if (tmp)
2328 return false;
2329 else
2330 m_crtEchoCancel = false;
2331 if (!m_device.valid())
2332 return false;
2333 bool ok = m_device.setEchoCancel(m_crtEchoCancel,m_echoTaps);
2334 if (m_crtEchoCancel)
2335 m_crtEchoCancel = ok;
2336 return ok;
2337 }
2338 if (param == "echotaps") {
2339 int tmp = value.toInteger();
2340 m_echoTaps = tmp >= 0 ? tmp : 0;
2341 return true;
2342 }
2343 if (param == "tonedetect") {
2344 bool tmp = value.toBoolean();
2345 if (tmp == m_crtDtmfDetect)
2346 return true;
2347 m_crtDtmfDetect = tmp;
2348 if (!m_device.valid())
2349 return true;
2350 bool ok = m_device.setDtmfDetect(m_crtDtmfDetect);
2351 if (m_crtDtmfDetect)
2352 m_crtDtmfDetect = ok;
2353 return ok;
2354 }
2355 if (param == "special_mode") {
2356 m_specialMode = value;
2357 return true;
2358 }
2359 return false;
2360 }
2361
2362 // Get circuit data
getParam(const String & param,String & value) const2363 bool ZapCircuit::getParam(const String& param, String& value) const
2364 {
2365 TempObjectCounter cnt(plugin.objectsCounter());
2366 if (param == "buflen")
2367 value = m_buflen;
2368 else if (param == "tonedetect")
2369 value = String::boolText(m_crtDtmfDetect);
2370 else if (param == "channel")
2371 value = m_device.channel();
2372 else if (param == "echocancel")
2373 value = String::boolText(m_crtEchoCancel);
2374 else if (param == "echotaps")
2375 value = m_echoTaps;
2376 else if (param == "alarms")
2377 value = m_device.alarmsText();
2378 else if (param == "driver")
2379 value = plugin.debugName();
2380 else
2381 return false;
2382 return true;
2383 }
2384
2385 // Get source or consumer
getObject(const String & name) const2386 void* ZapCircuit::getObject(const String& name) const
2387 {
2388 if (name == "ZapCircuit")
2389 return (void*)this;
2390 if (SignallingCircuit::status() == Connected) {
2391 if (name == "DataSource")
2392 return m_source;
2393 if (name == "DataConsumer")
2394 return m_consumer;
2395 }
2396 return SignallingCircuit::getObject(name);
2397 }
2398
2399 // Process incoming data
process()2400 bool ZapCircuit::process()
2401 {
2402 s_sourceAccessMutex.lock();
2403 RefPointer<ZapSource> src = m_source;
2404 s_sourceAccessMutex.unlock();
2405
2406 if (!(m_device.valid() && SignallingCircuit::status() == Connected && src))
2407 return false;
2408
2409 if (!m_device.select(10))
2410 return false;
2411 if (!m_device.canRead()) {
2412 if (m_device.event())
2413 checkEvents();
2414 return false;
2415 }
2416
2417 int r = m_device.recv(m_sourceBuffer.data(),m_sourceBuffer.length());
2418 if (m_device.event())
2419 checkEvents();
2420 if (r > 0) {
2421 if ((unsigned int)r != m_sourceBuffer.length())
2422 ::memset((unsigned char*)m_sourceBuffer.data() + r,m_idleValue,m_sourceBuffer.length() - r);
2423 src->Forward(m_sourceBuffer);
2424 return true;
2425 }
2426 return false;
2427 }
2428
2429 // Send an event through the circuit
sendEvent(SignallingCircuitEvent::Type type,NamedList * params)2430 bool ZapCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params)
2431 {
2432 XDebug(group(),DebugAll,"ZapCircuit(%u). sendEvent(%u) [%p]",code(),type,this);
2433 if (!m_canSend)
2434 return false;
2435 TempObjectCounter cnt(plugin.objectsCounter());
2436
2437 if (type == SignallingCircuitEvent::Dtmf) {
2438 const char* tones = 0;
2439 bool dtmf = true;
2440 bool dial = true;
2441 if (params) {
2442 tones = params->getValue("tone");
2443 dtmf = !params->getBoolValue("pulse",false);
2444 dial = params->getBoolValue("dial",true);
2445 }
2446 if (dial)
2447 return m_device.sendDtmf(tones,dtmf,ZapDevice::DialReplace,true,false);
2448 return m_device.sendDtmf(tones,dtmf,ZapDevice::DialAppend,false,true);
2449 }
2450
2451 Debug(group(),DebugNote,"ZapCircuit(%u). Unable to send unknown event %u [%p]",
2452 code(),type,this);
2453 return false;
2454 }
2455
2456 // Consume data sent by the consumer
consume(const DataBlock & data)2457 void ZapCircuit::consume(const DataBlock& data)
2458 {
2459 if (!(SignallingCircuit::status() >= Special && m_canSend && data.length()))
2460 return;
2461
2462 // Copy data in buffer
2463 // Throw old data on buffer overrun
2464 m_consTotal += data.length();
2465 if (m_consBuffer.length() + data.length() <= m_consBufMax)
2466 m_consBuffer += data;
2467 else {
2468 Debug(group(),DebugAll,
2469 "ZapCircuit(%u). Buffer overrun old=%u channel=%u (%d: %s) [%p]",
2470 code(),m_consBuffer.length(),m_device.channel(),m_errno,
2471 ::strerror(m_errno),this);
2472 m_consErrors++;
2473 m_consErrorBytes += m_consBuffer.length();
2474 m_consBuffer = data;
2475 }
2476
2477 // Send buffer. Stop on error
2478 while (m_consBuffer.length() >= m_buflen) {
2479 int w = m_device.write(m_consBuffer.data(),m_buflen);
2480 if (w <= 0) {
2481 m_errno = errno;
2482 break;
2483 }
2484 m_errno = 0;
2485 m_consBuffer.cut(-w);
2486 XDebug(group(),DebugAll,"ZapCircuit(%u). Sent %d bytes. Remaining: %u [%p]",
2487 code(),w,m_consBuffer.length(),this);
2488 }
2489 }
2490
2491 // Close device. Stop worker. Remove source consumer. Change status. Release memory if requested
2492 // Reset echo canceller and tone detector if the device is not closed
cleanup(bool release,Status stat,bool stop)2493 void ZapCircuit::cleanup(bool release, Status stat, bool stop)
2494 {
2495 if (stop || release) {
2496 ZapWorkerClient::stop();
2497 m_device.close();
2498 }
2499 if (m_consumer) {
2500 if (m_consErrors)
2501 Debug(group(),DebugNote,
2502 "ZapCircuit(%u). Consumer errors: %u. Lost: %u/%u [%p]",
2503 code(),m_consErrors,m_consErrorBytes,m_consTotal,this);
2504 TelEngine::destruct(m_consumer);
2505 }
2506 if (m_source) {
2507 s_sourceAccessMutex.lock();
2508 ZapSource* tmp = m_source;
2509 m_source = 0;
2510 s_sourceAccessMutex.unlock();
2511 if (tmp) {
2512 tmp->clear();
2513 TelEngine::destruct(tmp);
2514 }
2515 }
2516 if (release) {
2517 SignallingCircuit::destroyed();
2518 return;
2519 }
2520 status(stat);
2521 m_specialMode.clear();
2522 m_sourceBuffer.clear();
2523 m_consBuffer.clear();
2524 m_consErrors = m_consErrorBytes = m_consTotal = 0;
2525 // Reset echo canceller and tone detector
2526 if (m_device.valid() && (m_crtEchoCancel != m_echoCancel))
2527 m_device.setEchoCancel(m_echoCancel,m_echoTaps);
2528 m_crtEchoCancel = m_echoCancel;
2529 if (m_device.valid() && (m_crtDtmfDetect != m_dtmfDetect))
2530 m_device.setDtmfDetect(m_dtmfDetect);
2531 m_crtDtmfDetect = m_dtmfDetect;
2532 }
2533
2534 // Update format, echo canceller, dtmf detection
setFormat(ZapDevice::Format format)2535 bool ZapCircuit::setFormat(ZapDevice::Format format)
2536 {
2537 m_device.flushBuffers();
2538 if (!m_device.setFormat(format))
2539 return false;
2540 if (m_crtEchoCancel)
2541 m_crtEchoCancel = m_device.setEchoCancel(m_crtEchoCancel,m_echoTaps);
2542 if (m_crtDtmfDetect)
2543 m_crtDtmfDetect = m_device.setDtmfDetect(true);
2544 else
2545 m_device.setDtmfDetect(false);
2546 return true;
2547 }
2548
2549 // Get events
checkEvents()2550 void ZapCircuit::checkEvents()
2551 {
2552 char c = 0;
2553 int event = m_device.getEvent(c);
2554 if (!event)
2555 return;
2556 switch (event) {
2557 case ZapDevice::DtmfDown:
2558 case ZapDevice::DtmfUp:
2559 if (!m_crtDtmfDetect) {
2560 DDebug(group(),DebugAll,"ZapCircuit(%u). Ignoring DTMF '%s'=%c [%p]",
2561 code(),lookup(event,s_events,""),c,this);
2562 return;
2563 }
2564 if (event == ZapDevice::DtmfUp)
2565 enqueueDigit(true,c);
2566 else
2567 DDebug(group(),DebugAll,"ZapCircuit(%u). Ignoring '%s'=%c [%p]",
2568 code(),lookup(event,s_events,""),c,this);
2569 return;
2570 case ZapDevice::Alarm:
2571 case ZapDevice::NoAlarm:
2572 if (event == ZapDevice::Alarm) {
2573 if (!m_device.checkAlarms())
2574 return;
2575 SignallingCircuitEvent* e = new SignallingCircuitEvent(this,
2576 SignallingCircuitEvent::Alarm,lookup(event,s_events));
2577 e->addParam("alarms",m_device.alarmsText());
2578 enqueueEvent(e);
2579 }
2580 else {
2581 m_device.resetAlarms();
2582 enqueueEvent(event,SignallingCircuitEvent::NoAlarm);
2583 }
2584 return;
2585 default: ;
2586 }
2587 if (processEvent(event,c))
2588 return;
2589 enqueueEvent(event,SignallingCircuitEvent::Unknown);
2590 }
2591
2592 // Create source buffer and data source and consumer
createData()2593 void ZapCircuit::createData()
2594 {
2595 m_sourceBuffer.assign(0,m_buflen);
2596 const char* format = lookup(m_format,s_formats,"alaw");
2597 m_source = new ZapSource(this,format);
2598 if (m_canSend)
2599 m_consumer = new ZapConsumer(this,format);
2600 }
2601
2602 // Enqueue received events
enqueueEvent(SignallingCircuitEvent * e)2603 inline bool ZapCircuit::enqueueEvent(SignallingCircuitEvent* e)
2604 {
2605 if (e) {
2606 addEvent(e);
2607 DDebug(group(),e->type()!=SignallingCircuitEvent::Unknown?DebugAll:DebugStub,
2608 "ZapCircuit(%u). Enqueued event '%s' [%p]",code(),e->c_str(),this);
2609 }
2610 return true;
2611 }
2612
2613 // Enqueue received events
enqueueEvent(int event,SignallingCircuitEvent::Type type)2614 inline bool ZapCircuit::enqueueEvent(int event, SignallingCircuitEvent::Type type)
2615 {
2616 return enqueueEvent(new SignallingCircuitEvent(this,type,lookup(event,s_events)));
2617 }
2618
2619 // Enqueue received digits
enqueueDigit(bool tone,char digit)2620 bool ZapCircuit::enqueueDigit(bool tone, char digit)
2621 {
2622 char digits[2] = {digit,0};
2623 SignallingCircuitEvent* e = 0;
2624
2625 if (tone) {
2626 e = new SignallingCircuitEvent(this,SignallingCircuitEvent::Dtmf,
2627 lookup(ZapDevice::DtmfUp,s_events));
2628 e->addParam("tone",digits);
2629 }
2630 else {
2631 e = new SignallingCircuitEvent(this,SignallingCircuitEvent::PulseDigit,
2632 lookup(ZapDevice::PulseDigit,s_events));
2633 e->addParam("pulse",digits);
2634 }
2635 return enqueueEvent(e);
2636 }
2637
2638
2639 /**
2640 * ZapAnalogCircuit
2641 */
2642 // Change circuit status. Clear events on status change
2643 // New status is Reserved: Open device and start worker if old status is not Connected
2644 // New status is Connect: Create source/consumer
2645 // Cleanup on disconnect
status(Status newStat,bool sync)2646 bool ZapAnalogCircuit::status(Status newStat, bool sync)
2647 {
2648 if (SignallingCircuit::status() == newStat)
2649 return true;
2650 if (SignallingCircuit::status() == Missing) {
2651 Debug(group(),DebugNote,
2652 "ZapCircuit(%u). Can't change status to '%u'. Circuit is missing [%p]",
2653 code(),newStat,this);
2654 return false;
2655 }
2656 TempObjectCounter cnt(plugin.objectsCounter());
2657 // Allow status change for the following values
2658 switch (newStat) {
2659 case Missing:
2660 case Disabled:
2661 case Idle:
2662 case Reserved:
2663 case Special:
2664 case Connected:
2665 break;
2666 default: ;
2667 Debug(group(),DebugStub,
2668 "ZapCircuit(%u). Can't change status to unhandled value %u [%p]",
2669 code(),newStat,this);
2670 return false;
2671 }
2672
2673 Status oldStat = SignallingCircuit::status();
2674 if (!SignallingCircuit::status(newStat,sync))
2675 return false;
2676 clearEvents();
2677 if (!Engine::exiting())
2678 DDebug(group(),DebugAll,"ZapCircuit(%u). Changed status to %u [%p]",
2679 code(),newStat,this);
2680
2681 if (newStat < Special && m_device.valid())
2682 m_device.flushBuffers();
2683
2684 if (newStat == Reserved) {
2685 // Just cleanup if old status was Connected or the device is already valid
2686 // Otherwise: open device and start worker
2687 if (oldStat == Connected || m_device.valid())
2688 cleanup(false,Reserved,false);
2689 else {
2690 String addr;
2691 if (group())
2692 addr << group()->debugName() << "/";
2693 addr << code();
2694 if (m_device.open(0,m_buflen) && ZapWorkerClient::start(m_priority,group(),addr))
2695 setFormat(m_format);
2696 else
2697 cleanup(false,Idle,true);
2698 }
2699 return SignallingCircuit::status() == Reserved;
2700 }
2701 else if (newStat >= Special) {
2702 if (m_device.valid()) {
2703 createData();
2704 if (newStat == Special) {
2705 Message m("circuit.special");
2706 m.userData(this);
2707 if (group())
2708 m.addParam("group",group()->toString());
2709 if (span())
2710 m.addParam("span",span()->toString());
2711 if (m_specialMode)
2712 m.addParam("mode",m_specialMode);
2713 if (!Engine::dispatch(m))
2714 cleanup(false,Idle,true);
2715 }
2716 }
2717 else
2718 cleanup(false,Idle,true);
2719 return SignallingCircuit::status() == newStat;
2720 }
2721 return true;
2722 }
2723
2724 // Get circuit data
getParam(const String & param,String & value) const2725 bool ZapAnalogCircuit::getParam(const String& param, String& value) const
2726 {
2727 if (param == "hook") {
2728 value = String::boolText(m_hook);
2729 return true;
2730 }
2731 return ZapCircuit::getParam(param,value);
2732 }
2733
2734 // Set line polarity
setParam(const String & param,const String & value)2735 bool ZapAnalogCircuit::setParam(const String& param, const String& value)
2736 {
2737 TempObjectCounter cnt(plugin.objectsCounter());
2738 if (param == "polarity") {
2739 if (!(m_device.valid() && value.isBoolean()))
2740 return false;
2741 int state = value.toBoolean() ? 1 : 0;
2742 return m_device.setPolarity(state,DebugNote);
2743 }
2744 return ZapCircuit::setParam(param,value);
2745 }
2746
2747 // Send an event
sendEvent(SignallingCircuitEvent::Type type,NamedList * params)2748 bool ZapAnalogCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params)
2749 {
2750 if (!m_canSend)
2751 return false;
2752
2753 if (type == SignallingCircuitEvent::Dtmf)
2754 return ZapCircuit::sendEvent(type,params);
2755
2756 TempObjectCounter cnt(plugin.objectsCounter());
2757 XDebug(group(),DebugAll,"ZapAnalogCircuit(%u). sendEvent(%u) [%p]",code(),type,this);
2758 switch (type) {
2759 case SignallingCircuitEvent::OnHook:
2760 if (!m_device.sendHook(ZapDevice::HookOn))
2761 return false;
2762 changeHook(true);
2763 return true;
2764 case SignallingCircuitEvent::OffHook:
2765 if (!m_device.sendHook(ZapDevice::HookOff))
2766 return false;
2767 changeHook(false);
2768 return true;
2769 case SignallingCircuitEvent::Polarity:
2770 if (!params)
2771 return false;
2772 return setParam("polarity",params->getValue("polarity"));
2773 case SignallingCircuitEvent::Wink:
2774 return m_device.sendHook(ZapDevice::HookWink);
2775 case SignallingCircuitEvent::Flash:
2776 return m_device.sendHook(ZapDevice::HookFlash);
2777 case SignallingCircuitEvent::RingBegin:
2778 return m_device.sendHook(ZapDevice::HookRing);
2779 case SignallingCircuitEvent::RingEnd:
2780 return m_device.sendHook(ZapDevice::HookRingOff);
2781 case SignallingCircuitEvent::StartLine:
2782 return m_device.sendHook(ZapDevice::HookStart);
2783 default: ;
2784 }
2785 return ZapCircuit::sendEvent(type,params);
2786 }
2787
2788 // Process additional events. Return false if not processed
processEvent(int event,char c)2789 bool ZapAnalogCircuit::processEvent(int event, char c)
2790 {
2791 switch (event) {
2792 case ZapDevice::RingerOn:
2793 return enqueueEvent(event,SignallingCircuitEvent::RingerOn);
2794 case ZapDevice::RingerOff:
2795 return enqueueEvent(event,SignallingCircuitEvent::RingerOff);
2796 #ifdef DAHDI_EVENT_REMOVED
2797 case ZapDevice::Removed:
2798 #endif
2799 case ZapDevice::OnHook:
2800 changeHook(true);
2801 return enqueueEvent(event,SignallingCircuitEvent::OnHook);
2802 case ZapDevice::RingBegin:
2803 m_device.setLinear(0,DebugAll);
2804 return enqueueEvent(event,SignallingCircuitEvent::RingBegin);
2805 case ZapDevice::OffHookRing:
2806 if (m_device.type() == ZapDevice::FXS) {
2807 changeHook(false);
2808 return enqueueEvent(event,SignallingCircuitEvent::OffHook);
2809 }
2810 return enqueueEvent(event,SignallingCircuitEvent::RingerOff);
2811 case ZapDevice::Polarity:
2812 return enqueueEvent(event,SignallingCircuitEvent::Polarity);
2813 case ZapDevice::WinkFlash:
2814 if (m_hook)
2815 return enqueueEvent(event,SignallingCircuitEvent::Wink);
2816 return enqueueEvent(event,SignallingCircuitEvent::Flash);
2817 case ZapDevice::HookComplete:
2818 return enqueueEvent(event,SignallingCircuitEvent::LineStarted);
2819 case ZapDevice::DialComplete:
2820 return enqueueEvent(event,SignallingCircuitEvent::DialComplete);
2821 case ZapDevice::PulseDigit:
2822 return enqueueDigit(false,c);
2823 case ZapDevice::PulseStart:
2824 return enqueueEvent(event,SignallingCircuitEvent::PulseStart);
2825 case ZapDevice::Timeout:
2826 return enqueueEvent(event,SignallingCircuitEvent::Timeout);
2827 case ZapDevice::BitsChanged:
2828 case ZapDevice::TimerPing:
2829 DDebug(group(),DebugStub,"ZapCircuit(%u). Unhandled event %u [%p]",
2830 code(),event,this);
2831 break;
2832 default:
2833 Debug(group(),DebugStub,"ZapCircuit(%u). Unknown event %u [%p]",
2834 code(),event,this);
2835 }
2836 return false;
2837 }
2838
2839 // Process incoming data
process()2840 bool ZapAnalogCircuit::process()
2841 {
2842 if (!(m_device.valid() && SignallingCircuit::status() != SignallingCircuit::Disabled))
2843 return false;
2844
2845 m_device.pollHook();
2846 checkEvents();
2847
2848 s_sourceAccessMutex.lock();
2849 RefPointer<ZapSource> src = m_source;
2850 s_sourceAccessMutex.unlock();
2851
2852 if (!(src && m_device.select(10) && m_device.canRead()))
2853 return false;
2854
2855 int r = m_device.recv(m_sourceBuffer.data(),m_sourceBuffer.length());
2856 if (m_device.event())
2857 checkEvents();
2858 if (r > 0) {
2859 if ((unsigned int)r != m_sourceBuffer.length())
2860 ::memset((unsigned char*)m_sourceBuffer.data() + r,m_idleValue,m_sourceBuffer.length() - r);
2861 XDebug(group(),DebugAll,"ZapCircuit(%u). Forwarding %u bytes [%p]",
2862 code(),m_sourceBuffer.length(),this);
2863 src->Forward(m_sourceBuffer);
2864 return true;
2865 }
2866
2867 return false;
2868 }
2869
2870 // Change hook state if different
changeHook(bool hook)2871 void ZapAnalogCircuit::changeHook(bool hook)
2872 {
2873 if (m_hook == hook)
2874 return;
2875 DDebug(group(),DebugInfo,"ZapCircuit(%u). Hook state changed to %s [%p]",
2876 code(),hook?"ON":"OFF",this);
2877 m_hook = hook;
2878 }
2879
2880
2881 /**
2882 * ZapSource
2883 */
setAddr(String & addr,ZapCircuit * cic)2884 inline void setAddr(String& addr, ZapCircuit* cic)
2885 {
2886 #ifdef XDEBUG
2887 if (cic) {
2888 if (cic->group())
2889 addr << cic->group()->debugName() << "/";
2890 addr << cic->code();
2891 }
2892 else
2893 addr = -1;
2894 #endif
2895 }
2896
ZapSource(ZapCircuit * circuit,const char * format)2897 ZapSource::ZapSource(ZapCircuit* circuit, const char* format)
2898 : DataSource(format)
2899 {
2900 setAddr(m_address,circuit);
2901 XDebug(&plugin,DebugAll,"ZapSource::ZapSource() cic=%s [%p]",m_address.c_str(),this);
2902 }
2903
~ZapSource()2904 ZapSource::~ZapSource()
2905 {
2906 XDebug(&plugin,DebugAll,"ZapSource::~ZapSource() cic=%s [%p]",m_address.c_str(),this);
2907 }
2908
2909
2910 /**
2911 * ZapConsumer
2912 */
ZapConsumer(ZapCircuit * circuit,const char * format)2913 ZapConsumer::ZapConsumer(ZapCircuit* circuit, const char* format)
2914 : DataConsumer(format),
2915 m_circuit(circuit)
2916 {
2917 setAddr(m_address,circuit);
2918 XDebug(&plugin,DebugAll,"ZapConsumer::ZapConsumer() cic=%s [%p]",m_address.c_str(),this);
2919 }
2920
~ZapConsumer()2921 ZapConsumer::~ZapConsumer()
2922 {
2923 XDebug(&plugin,DebugAll,"ZapConsumer::~ZapConsumer() cic=%s [%p]",m_address.c_str(),this);
2924 }
2925
2926
2927 /**
2928 * ZapModule
2929 */
2930 String ZapModule::s_statusCmd[StatusCmdCount] = {"spans","channels","all"};
2931
ZapModule()2932 ZapModule::ZapModule()
2933 : Module("zaptel","misc",true),
2934 m_init(false),
2935 m_count(0),
2936 m_active(0)
2937 {
2938 Output("Loaded module Zaptel");
2939 m_prefix << name() << "/";
2940 m_statusCmd << "status " << name();
2941 }
2942
~ZapModule()2943 ZapModule::~ZapModule()
2944 {
2945 Output("Unloading module Zaptel");
2946 }
2947
append(ZapDevice * dev)2948 void ZapModule::append(ZapDevice* dev)
2949 {
2950 if (!dev)
2951 return;
2952 Lock lock(this);
2953 m_devices.append(dev)->setDelete(false);
2954 m_count = m_devices.count();
2955 }
2956
remove(ZapDevice * dev)2957 void ZapModule::remove(ZapDevice* dev)
2958 {
2959 if (!dev)
2960 return;
2961 Lock lock(this);
2962 m_devices.remove(dev,false);
2963 m_count = m_devices.count();
2964 }
2965
initialize()2966 void ZapModule::initialize()
2967 {
2968 Output("Initializing module Zaptel");
2969
2970 Configuration cfg(Engine::configFile("zapcard"));
2971 cfg.load();
2972
2973 NamedList dummy("");
2974 NamedList* general = cfg.getSection("general");
2975 if (!general)
2976 general = &dummy;
2977
2978 ZapDevice dev(0,false,true);
2979 if (!dev.valid())
2980 Debug(this,DebugNote,"Failed to open zaptel device: driver might not be loaded");
2981
2982 int dtmfLen = 0;
2983 if (!m_init) {
2984 m_init = true;
2985 setup();
2986 installRelay(Command);
2987 // Set DTMF/MF length
2988 if (dev.valid() && dev.dialParams(false,dtmfLen,dtmfLen)) {
2989 dtmfLen = general->getIntValue("tonelength",dtmfLen);
2990 dev.dialParams(true,dtmfLen,dtmfLen);
2991 }
2992 }
2993 if (dev.valid() && debugAt(DebugAll)) {
2994 NamedList nl("");
2995 dev.getVersion(nl);
2996 dtmfLen = 0;
2997 dev.dialParams(false,dtmfLen,dtmfLen);
2998 Debug(this,DebugAll,"version=%s echocanceller=%s tonelength=%d samples",
2999 nl.getValue("version"),nl.getValue("echocanceller"),dtmfLen);
3000 }
3001 }
3002
3003
3004 // Find a device by its Zaptel channel
findZaptelChan(int chan)3005 ZapDevice* ZapModule::findZaptelChan(int chan)
3006 {
3007 Lock lock(this);
3008 for (ObjList* o = m_devices.skipNull(); o; o = o->skipNext()) {
3009 ZapDevice* dev = static_cast<ZapDevice*>(o->get());
3010 if ((int)dev->channel() == chan)
3011 return dev;
3012 }
3013 return 0;
3014 }
3015
received(Message & msg,int id)3016 bool ZapModule::received(Message& msg, int id)
3017 {
3018 if (id == Status) {
3019 String dest = msg.getValue("module");
3020
3021 // Module status
3022 if (!dest || dest == name()) {
3023 Module::msgStatus(msg);
3024 return false;
3025 }
3026
3027 Lock lock(this);
3028
3029 // Device status
3030 if (dest.startSkip(prefix(),false)) {
3031 ZapDevice* dev = findZaptelChan((unsigned int)dest.toInteger());
3032 if (!dev)
3033 return false;
3034 msg.retValue().clear();
3035 msg.retValue() << "name=" << dev->zapName();
3036 msg.retValue() << ",module=" << name();
3037 msg.retValue() << ",type=" << lookup(dev->type(),s_types);
3038 if (dev->span() != -1) {
3039 msg.retValue() << ",zapteltype=" << lookup(dev->zapsig(),s_zaptelSig);
3040 msg.retValue() << ",span=" << dev->span();
3041 msg.retValue() << ",spanpos=" << dev->spanPos();
3042 msg.retValue() << ",alarms=" << dev->alarmsText();
3043 }
3044 else
3045 msg.retValue() << ",zapteltype=not-configured,span=,spanpos=,alarms=";
3046 msg.retValue() << ",address=" << dev->address();
3047 msg.retValue() << "\r\n";
3048 return true;
3049 }
3050
3051 // Additional commands
3052 if (dest.startSkip(name(),false)) {
3053 dest.trimBlanks();
3054 int cmd = 0;
3055 for (; cmd < StatusCmdCount; cmd++)
3056 if (s_statusCmd[cmd] == dest)
3057 break;
3058 if (cmd == ZapSpans) {
3059 ZapDevice* ctl = new ZapDevice(0);
3060 NamedList ver("");
3061 ctl->getVersion(ver);
3062 msg.retValue().clear();
3063 msg.retValue() << "module=" << name() << "," << s_spanParamsHdr;
3064 msg.retValue() << ";version=" << ver.getValue("version");
3065 msg.retValue() << ",echocanceller=" << ver.getValue("echocanceller");
3066 for (int span = 1; true; span++) {
3067 NamedList p("");
3068 int total = 0;
3069 bool ok = ctl->getSpanInfo(span,p,&total);
3070 if (span == 1)
3071 msg.retValue() << ",count=" << total;
3072 if (!ok)
3073 break;
3074 // format=Channels|Total|Alarms|Name|Description
3075 msg.retValue() << ";" << span << "=" << p.getValue("configured-chans");
3076 msg.retValue() << "|" << p.getValue("total-chans");
3077 msg.retValue() << "|" << p.getValue("alarmstext");
3078 msg.retValue() << "|" << p.getValue("name");
3079 msg.retValue() << "|" << p.getValue("desc");
3080 }
3081 TelEngine::destruct(ctl);
3082 }
3083 else if (cmd == ZapChannels || cmd == ZapChannelsAll) {
3084 ZapDevice* ctl = new ZapDevice(0);
3085 String s;
3086 unsigned int chan = 0;
3087 for (int span = 1; ctl->valid(); span++) {
3088 // Check span
3089 NamedList p("");
3090 if (!ctl->getSpanInfo(span,p))
3091 break;
3092
3093 // Get info
3094 int chans = p.getIntValue("total-chans");
3095 for (int i = 0; i < chans; i++) {
3096 chan++;
3097 // Get device
3098 // Create or reset debuger to avoid unwanted debug output to console
3099 bool created = false;
3100 bool opened = false;
3101 ZapDevice* dev = findZaptelChan(chan);
3102 if (!dev) {
3103 dev = new ZapDevice(chan);
3104 created = true;
3105 }
3106 else if (dev->owner())
3107 dev->owner()->debugEnabled(false);
3108 if (!dev->valid()) {
3109 dev->open(0,0);
3110 opened = true;
3111 }
3112
3113 bool show = (dev->span() == span) || (cmd == ZapChannelsAll);
3114 if (show) {
3115 // format=Type|ZaptelType|Span|SpanPos|Alarms|Address
3116 s << ";" << dev->channel() << "=" << lookup(dev->type(),s_types);
3117 if (dev->span() == span) {
3118 s << "|" << lookup(dev->zapsig(),s_zaptelSig);
3119 s << "|" << dev->span();
3120 s << "|" << dev->spanPos();
3121 s << "|" << dev->alarmsText();
3122 }
3123 else
3124 s << "|not-configured|||";
3125 s << "|" << dev->address();
3126 }
3127
3128 // Cleanup if we opened/created the device
3129 if (created) {
3130 TelEngine::destruct(dev);
3131 continue;
3132 }
3133 if (opened)
3134 dev->close();
3135 if (dev->owner())
3136 dev->owner()->debugEnabled(true);
3137 }
3138 }
3139 TelEngine::destruct(ctl);
3140
3141 msg.retValue().clear();
3142 msg.retValue() << "module=" << name() << "," << s_chanParamsHdr;
3143 msg.retValue() << ";used=" << m_count << ",total=" << chan;
3144 msg.retValue() << s;
3145 }
3146 else
3147 return false;
3148 msg.retValue() << "\r\n";
3149 return true;
3150 }
3151
3152 return false;
3153 }
3154 return Module::received(msg,id);
3155 }
3156
statusModule(String & str)3157 void ZapModule::statusModule(String& str)
3158 {
3159 Module::statusModule(str);
3160 str.append(s_chanParamsHdr,",");
3161 }
3162
statusParams(String & str)3163 void ZapModule::statusParams(String& str)
3164 {
3165 Module::statusParams(str);
3166 str.append("active=",",") << m_active;
3167 str << ",count=" << m_count;
3168 }
3169
statusDetail(String & str)3170 void ZapModule::statusDetail(String& str)
3171 {
3172 // format=Type|ZaptelType|Span|SpanPos|Alarms|Address
3173 for (ObjList* o = m_devices.skipNull(); o; o = o->skipNext()) {
3174 ZapDevice* dev = static_cast<ZapDevice*>(o->get());
3175 str.append(String(dev->channel()),";") << "=" << lookup(dev->type(),s_types);
3176 str << "|" << lookup(dev->zapsig(),s_zaptelSig);
3177 str << "|" << dev->span();
3178 str << "|" << dev->spanPos();
3179 str << "|" << dev->alarmsText();
3180 str << "|" << dev->address();
3181 }
3182 }
3183
commandComplete(Message & msg,const String & partLine,const String & partWord)3184 bool ZapModule::commandComplete(Message& msg, const String& partLine,
3185 const String& partWord)
3186 {
3187 bool ok = Module::commandComplete(msg,partLine,partWord);
3188 if (!partLine.startsWith("status"))
3189 return ok;
3190 Lock lock(this);
3191 if (name().startsWith(partWord)) {
3192 if (m_devices.skipNull())
3193 msg.retValue().append(prefix(),"\t");
3194 return ok;
3195 }
3196 if (partLine == m_statusCmd) {
3197 for (unsigned int i = 0; i < StatusCmdCount; i++)
3198 itemComplete(msg.retValue(),s_statusCmd[i],partWord);
3199 return true;
3200 }
3201 if (partWord.startsWith(prefix())) {
3202 for (ObjList* o = m_devices.skipNull(); o; o = o->skipNext())
3203 itemComplete(msg.retValue(),static_cast<ZapDevice*>(o->get())->zapName(),partWord);
3204 return true;
3205 }
3206 return ok;
3207 }
3208
3209 }; // anonymous namespace
3210
3211 #endif /* _WINDOWS */
3212
3213 /* vi: set ts=8 sw=4 sts=4 noet: */
3214