This source file includes following definitions.
- tdmv_api_wait_socket
- tdmv_api_open_span_chan
- __tdmv_api_open_span_chan
- wanpipe_swap_bits
- wp_open_range
- FIO_CONFIGURE_FUNCTION
- FIO_CONFIGURE_SPAN_FUNCTION
- FIO_OPEN_FUNCTION
- FIO_CLOSE_FUNCTION
- FIO_COMMAND_FUNCTION
- wanpipe_write_stats
- wanpipe_read_stats
- FIO_READ_FUNCTION
- FIO_WRITE_FUNCTION
- FIO_WAIT_FUNCTION
- FIO_SPAN_POLL_EVENT_FUNCTION
- FIO_GET_ALARMS_FUNCTION
- wanpipe_channel_process_event
- FIO_CHANNEL_NEXT_EVENT_FUNCTION
- FIO_SPAN_NEXT_EVENT_FUNCTION
- FIO_CHANNEL_DESTROY_FUNCTION
- FIO_IO_LOAD_FUNCTION
- FIO_IO_UNLOAD_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 #ifdef __sun
43 #include <unistd.h>
44 #include <stropts.h>
45 #endif
46 #include "private/ftdm_core.h"
47 #ifndef __WINDOWS__
48 #include <poll.h>
49 #include <sys/socket.h>
50 #endif
51 #include "libsangoma.h"
52
53 #if defined(__WINDOWS__)
54
55 #define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan
56 #define sangoma_open_tdmapi_span sangoma_open_api_span
57 #define sangoma_open_tdmapi_ctrl sangoma_open_api_ctrl
58 #define sangoma_tdm_get_fe_status sangoma_get_fe_status
59 #define sangoma_socket_close sangoma_close
60 #define sangoma_tdm_get_hw_coding sangoma_get_hw_coding
61 #define sangoma_tdm_set_fe_status sangoma_set_fe_status
62 #define sangoma_tdm_get_link_status sangoma_get_link_status
63 #define sangoma_tdm_flush_bufs sangoma_flush_bufs
64 #define sangoma_tdm_cmd_exec sangoma_cmd_exec
65 #define sangoma_tdm_read_event sangoma_read_event
66 #define sangoma_readmsg_tdm sangoma_readmsg
67 #define sangoma_readmsg_socket sangoma_readmsg
68 #define sangoma_sendmsg_socket sangoma_writemsg
69 #define sangoma_writemsg_tdm sangoma_writemsg
70 #define sangoma_create_socket_intr sangoma_open_api_span_chan
71 #endif
72
73
74
75
76 #ifdef LIBSANGOMA_VERSION
77 #if LIBSANGOMA_VERSION_CODE < LIBSANGOMA_VERSION(3,0,0)
78 #undef LIBSANGOMA_VERSION
79 #endif
80 #endif
81
82
83
84
85 typedef enum {
86 WP_RINGING = (1 << 0)
87 } wp_flag_t;
88
89
90
91
92 static struct {
93 uint32_t codec_ms;
94 uint32_t wink_ms;
95 uint32_t flash_ms;
96 uint32_t ring_on_ms;
97 uint32_t ring_off_ms;
98 } wp_globals;
99
100
101
102 FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
103 FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event);
104 FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event);
105
106
107
108
109
110
111
112
113
114
115
116
117 static __inline__ int tdmv_api_wait_socket(ftdm_channel_t *ftdmchan, int timeout, int *flags)
118 {
119
120 #ifdef LIBSANGOMA_VERSION
121 int err;
122 uint32_t inflags = *flags;
123 uint32_t outflags = 0;
124 sangoma_wait_obj_t *sangoma_wait_obj = ftdmchan->io_data;
125
126 if (timeout == -1) {
127 timeout = SANGOMA_WAIT_INFINITE;
128 }
129
130 err = sangoma_waitfor(sangoma_wait_obj, inflags, &outflags, timeout);
131 *flags = 0;
132 if (err == SANG_STATUS_SUCCESS) {
133 *flags = outflags;
134 err = 1;
135 }
136 if (err == SANG_STATUS_APIPOLL_TIMEOUT) {
137 err = 0;
138 }
139 return err;
140 #else
141 struct pollfd pfds[1];
142 int res;
143
144 memset(&pfds[0], 0, sizeof(pfds[0]));
145 pfds[0].fd = ftdmchan->sockfd;
146 pfds[0].events = *flags;
147 res = poll(pfds, 1, timeout);
148 *flags = 0;
149
150 if (pfds[0].revents & POLLERR) {
151 res = -1;
152 }
153
154 if (res > 0) {
155 *flags = pfds[0].revents;
156 }
157
158 return res;
159 #endif
160
161 }
162
163
164
165
166
167
168
169 static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan)
170 {
171 return sangoma_open_tdmapi_span_chan(span, chan);
172 }
173
174 #ifdef LIBSANGOMA_VERSION
175 static __inline__ sng_fd_t __tdmv_api_open_span_chan(int span, int chan)
176 {
177 return __sangoma_open_tdmapi_span_chan(span, chan);
178 }
179 #endif
180
181 static ftdm_io_interface_t wanpipe_interface;
182
183
184
185
186
187
188 static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
189 {
190 unsigned char swapped_bits = 0x0;
191 if (cas_bits & 0x8) {
192 swapped_bits |= 0x1;
193 }
194 if (cas_bits & 0x4) {
195 swapped_bits |= 0x2;
196 }
197 if (cas_bits & 0x2) {
198 swapped_bits |= 0x4;
199 }
200 if (cas_bits & 0x1) {
201 swapped_bits |= 0x8;
202 }
203 return swapped_bits;
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217
218 static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start, unsigned end, ftdm_chan_type_t type, char *name, char *number, unsigned char cas_bits)
219 {
220 unsigned configured = 0, x;
221 #ifdef LIBSANGOMA_VERSION
222 sangoma_status_t sangstatus;
223 sangoma_wait_obj_t *sangoma_wait_obj;
224 #endif
225
226 if (type == FTDM_CHAN_TYPE_CAS) {
227 ftdm_log(FTDM_LOG_DEBUG, "Configuring Wanpipe CAS channels with abcd == 0x%X\n", cas_bits);
228 }
229 for(x = start; x < end; x++) {
230 ftdm_channel_t *chan;
231 ftdm_socket_t sockfd = FTDM_INVALID_SOCKET;
232 const char *dtmf = "none";
233 if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == FTDM_TRUNK_T1 && x == 24) {
234 #ifdef LIBSANGOMA_VERSION
235 sockfd = __tdmv_api_open_span_chan(spanno, x);
236 #else
237 ftdm_log(FTDM_LOG_ERROR, "span %d channel %d cannot be configured as smg_prid_nfas, you need to compile freetdm with newer libsangoma\n", spanno, x);
238 #endif
239 } else {
240 sockfd = tdmv_api_open_span_chan(spanno, x);
241 }
242
243 if (sockfd == FTDM_INVALID_SOCKET) {
244 ftdm_log(FTDM_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
245 continue;
246 }
247
248 if (ftdm_span_add_channel(span, sockfd, type, &chan) == FTDM_SUCCESS) {
249 wanpipe_tdm_api_t tdm_api;
250 memset(&tdm_api, 0, sizeof(tdm_api));
251 #ifdef LIBSANGOMA_VERSION
252
253
254
255
256 sangstatus = sangoma_wait_obj_create(&sangoma_wait_obj, sockfd, SANGOMA_DEVICE_WAIT_OBJ_SIG);
257 if (sangstatus != SANG_STATUS_SUCCESS) {
258 ftdm_log(FTDM_LOG_ERROR, "failure create waitable object for s%dc%d\n", spanno, x);
259 continue;
260 }
261 chan->io_data = sangoma_wait_obj;
262 #endif
263
264 chan->physical_span_id = spanno;
265 chan->physical_chan_id = x;
266 chan->rate = 8000;
267
268 if (type == FTDM_CHAN_TYPE_FXS
269 || type == FTDM_CHAN_TYPE_FXO
270 || type == FTDM_CHAN_TYPE_CAS
271 || type == FTDM_CHAN_TYPE_B) {
272 int err;
273
274 dtmf = "software";
275
276 err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
277
278 if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
279 chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
280 } else {
281 chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
282 }
283
284 err = sangoma_tdm_get_hw_dtmf(chan->sockfd, &tdm_api);
285 if (err > 0) {
286 ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_DTMF_DETECT);
287 dtmf = "hardware";
288 }
289
290 err = sangoma_tdm_get_hw_ec(chan->sockfd, &tdm_api);
291 if (err > 0) {
292 ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC);
293 }
294
295 #ifdef WP_API_FEATURE_HWEC_PERSIST
296 err = sangoma_tdm_get_hwec_persist_status(chan->sockfd, &tdm_api);
297 if (err == 0) {
298 ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE);
299 }
300 #else
301 if (span->trunk_type == FTDM_TRUNK_BRI || span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
302 ftdm_log(FTDM_LOG_WARNING, "WP_API_FEATURE_HWEC_PERSIST feature is not supported \
303 with your version of libsangoma, you should update your Wanpipe drivers\n");
304
305 }
306 #endif
307
308 }
309
310 #ifdef LIBSANGOMA_VERSION
311 if (type == FTDM_CHAN_TYPE_FXS) {
312 if (sangoma_tdm_disable_ring_trip_detect_events(chan->sockfd, &tdm_api)) {
313
314
315 ftdm_log(FTDM_LOG_WARNING, "Failed to disable ring trip events in channel s%dc%d\n", spanno, x);
316 }
317 }
318 #endif
319 #if 0
320 if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
321
322 int err=sangoma_set_rm_rxflashtime(chan->sockfd, &tdm_api, wp_globals.flash_ms);
323 if (err == 0) {
324 ftdm_log(FTDM_LOG_ERROR, "flash enabled s%dc%d\n", spanno, x);
325 } else {
326 ftdm_log(FTDM_LOG_ERROR, "flash disabled s%dc%d\n", spanno, x);
327 }
328 }
329 #endif
330
331 if (type == FTDM_CHAN_TYPE_CAS || type == FTDM_CHAN_TYPE_EM) {
332 #ifdef LIBSANGOMA_VERSION
333 sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id, wanpipe_swap_bits(cas_bits));
334
335
336
337
338 if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
339 ftdm_log(FTDM_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
340 continue;
341 }
342 sangoma_flush_bufs(chan->sockfd, &tdm_api);
343 sangoma_flush_event_bufs(chan->sockfd, &tdm_api);
344 #else
345
346
347
348
349
350
351 if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
352 ftdm_log(FTDM_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
353 }
354
355 sangoma_tdm_flush_bufs(chan->sockfd, &tdm_api);
356 sangoma_tdm_write_rbs(chan->sockfd,&tdm_api, wanpipe_swap_bits(cas_bits));
357 #endif
358 }
359
360 if (!ftdm_strlen_zero(name)) {
361 ftdm_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
362 }
363
364 if (!ftdm_strlen_zero(number)) {
365 ftdm_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
366 }
367 configured++;
368 ftdm_log_chan(chan, FTDM_LOG_INFO, "Configured wanpipe device fd:%d DTMF: %s\n", sockfd, dtmf);
369
370 } else {
371 ftdm_log(FTDM_LOG_ERROR, "ftdm_span_add_channel failed for wanpipe span %d channel %d\n", spanno, x);
372 }
373 }
374
375 return configured;
376 }
377
378
379
380
381
382
383
384
385
386 static FIO_CONFIGURE_FUNCTION(wanpipe_configure)
387 {
388 int num;
389
390 if (!strcasecmp(category, "defaults")) {
391 if (!strcasecmp(var, "codec_ms")) {
392 num = atoi(val);
393 if (num < 10 || num > 60) {
394 ftdm_log(FTDM_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
395 } else {
396 wp_globals.codec_ms = num;
397 }
398 } else if (!strcasecmp(var, "wink_ms")) {
399 num = atoi(val);
400 if (num < 50 || num > 3000) {
401 ftdm_log(FTDM_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
402 } else {
403 wp_globals.wink_ms = num;
404 }
405 } else if (!strcasecmp(var, "flash_ms")) {
406 num = atoi(val);
407 if (num < 50 || num > 3000) {
408 ftdm_log(FTDM_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
409 } else {
410 wp_globals.flash_ms = num;
411 }
412 } else if (!strcasecmp(var, "ring_on_ms")) {
413 num = atoi(val);
414 if (num < 500 || num > 5000) {
415 ftdm_log(FTDM_LOG_WARNING, "invalid ring_on_ms at line %d (valid range 500 to 5000)\n", lineno);
416 } else {
417 wp_globals.ring_on_ms = num;
418 }
419 } else if (!strcasecmp(var, "ring_off_ms")) {
420 num = atoi(val);
421 if (num < 500 || num > 5000) {
422 ftdm_log(FTDM_LOG_WARNING, "invalid ring_off_ms at line %d (valid range 500 to 5000)\n", lineno);
423 } else {
424 wp_globals.ring_off_ms = num;
425 }
426 }
427 }
428
429 return FTDM_SUCCESS;
430 }
431
432
433
434
435
436
437
438
439
440
441 static FIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
442 {
443 int items, i;
444 char *mydata, *item_list[10];
445 char *sp, *ch, *mx;
446 unsigned char cas_bits = 0;
447 int channo;
448 int spanno;
449 int top = 0;
450 unsigned configured = 0;
451
452 assert(str != NULL);
453
454
455 mydata = ftdm_strdup(str);
456 assert(mydata != NULL);
457
458
459 items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
460
461 for(i = 0; i < items; i++) {
462 sp = item_list[i];
463 if ((ch = strchr(sp, ':'))) {
464 *ch++ = '\0';
465 }
466
467 if (!(sp && ch)) {
468 ftdm_log(FTDM_LOG_ERROR, "No valid wanpipe span and channel was specified\n");
469 continue;
470 }
471
472 channo = atoi(ch);
473 spanno = atoi(sp);
474
475 if (channo < 0) {
476 ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
477 continue;
478 }
479
480 if (spanno < 0) {
481 ftdm_log(FTDM_LOG_ERROR, "Invalid span number %d\n", channo);
482 continue;
483 }
484
485 if ((mx = strchr(ch, '-'))) {
486 mx++;
487 top = atoi(mx) + 1;
488 } else {
489 top = channo + 1;
490 }
491
492
493 if (top < 0) {
494 ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
495 continue;
496 }
497 if (FTDM_CHAN_TYPE_CAS == type && ftdm_config_get_cas_bits(ch, &cas_bits)) {
498 ftdm_log(FTDM_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
499 continue;
500 }
501 configured += wp_open_range(span, spanno, channo, top, type, name, number, cas_bits);
502
503 }
504
505 ftdm_safe_free(mydata);
506
507 return configured;
508 }
509
510
511
512
513
514
515 static FIO_OPEN_FUNCTION(wanpipe_open)
516 {
517
518 wanpipe_tdm_api_t tdm_api;
519
520 memset(&tdm_api,0,sizeof(tdm_api));
521
522 sangoma_tdm_flush_bufs(ftdmchan->sockfd, &tdm_api);
523 sangoma_flush_stats(ftdmchan->sockfd, &tdm_api);
524 memset(&ftdmchan->iostats, 0, sizeof(ftdmchan->iostats));
525
526 if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) {
527 ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE;
528 } else {
529 ftdmchan->effective_codec = ftdmchan->native_codec;
530
531 sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, wp_globals.codec_ms);
532
533 ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
534 ftdmchan->effective_interval = ftdmchan->native_interval = wp_globals.codec_ms;
535 ftdmchan->packet_len = ftdmchan->native_interval * 8;
536 }
537
538 return FTDM_SUCCESS;
539 }
540
541
542
543
544
545
546 static FIO_CLOSE_FUNCTION(wanpipe_close)
547 {
548 #ifdef LIBSANGOMA_VERSION
549 sangoma_wait_obj_t *waitobj = ftdmchan->io_data;
550
551 sangoma_wait_obj_signal(waitobj);
552 #endif
553 return FTDM_SUCCESS;
554 }
555
556
557
558
559
560
561
562
563 static FIO_COMMAND_FUNCTION(wanpipe_command)
564 {
565 wanpipe_tdm_api_t tdm_api;
566 int err = 0;
567
568 memset(&tdm_api, 0, sizeof(tdm_api));
569
570 switch(command) {
571 case FTDM_COMMAND_OFFHOOK:
572 {
573 err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
574 if (err) {
575 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed");
576 return FTDM_FAIL;
577 }
578 ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
579 }
580 break;
581 case FTDM_COMMAND_ONHOOK:
582 {
583 err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
584 if (err) {
585 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
586 return FTDM_FAIL;
587 }
588 ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
589 }
590 break;
591 case FTDM_COMMAND_GENERATE_RING_ON:
592 {
593 err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
594 if (err) {
595 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
596 return FTDM_FAIL;
597 }
598 ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
599 ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
600 ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
601 }
602 break;
603 case FTDM_COMMAND_GENERATE_RING_OFF:
604 {
605 err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
606 if (err) {
607 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
608 return FTDM_FAIL;
609 }
610 ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
611 ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
612 }
613 break;
614 case FTDM_COMMAND_GET_INTERVAL:
615 {
616 err=sangoma_tdm_get_usr_period(ftdmchan->sockfd, &tdm_api);
617 if (err > 0 ) {
618 FTDM_COMMAND_OBJ_INT = err;
619 err=0;
620 }
621 }
622 break;
623 case FTDM_COMMAND_ENABLE_ECHOCANCEL:
624 {
625 #ifdef WP_API_FEATURE_EC_CHAN_STAT
626 err=sangoma_tdm_get_hwec_chan_status(ftdmchan->sockfd, &tdm_api);
627 if (err > 0) {
628
629 err = 0;
630 break;
631 }
632 #endif
633 err=sangoma_tdm_enable_hwec(ftdmchan->sockfd, &tdm_api);
634 if (err) {
635 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed");
636 return FTDM_FAIL;
637 }
638 }
639 break;
640 case FTDM_COMMAND_DISABLE_ECHOCANCEL:
641 {
642 #ifdef WP_API_FEATURE_EC_CHAN_STAT
643 err=sangoma_tdm_get_hwec_chan_status(ftdmchan->sockfd, &tdm_api);
644 if (!err) {
645
646 break;
647 }
648 #endif
649 err=sangoma_tdm_disable_hwec(ftdmchan->sockfd, &tdm_api);
650 if (err) {
651 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed");
652 return FTDM_FAIL;
653 }
654 }
655 break;
656 case FTDM_COMMAND_ENABLE_DTMF_DETECT:
657 {
658 #ifdef WP_API_FEATURE_DTMF_EVENTS
659 err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api);
660 if (err) {
661 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Enabling of Sangoma HW DTMF failed\n");
662 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Enable Failed");
663 return FTDM_FAIL;
664 }
665 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled DTMF events\n");
666 #else
667 return FTDM_NOTIMPL;
668 #endif
669 }
670 break;
671 case FTDM_COMMAND_DISABLE_DTMF_DETECT:
672 {
673 #ifdef WP_API_FEATURE_DTMF_EVENTS
674 err = sangoma_tdm_disable_dtmf_events(ftdmchan->sockfd, &tdm_api);
675 if (err) {
676 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Disabling of Sangoma HW DTMF failed\n");
677 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Disable Failed");
678 return FTDM_FAIL;
679 }
680 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Disabled DTMF events\n");
681 #else
682 return FTDM_NOTIMPL;
683 #endif
684 }
685 break;
686 case FTDM_COMMAND_ENABLE_LOOP:
687 {
688 #ifdef WP_API_FEATURE_LOOP
689 err=sangoma_tdm_enable_loop(ftdmchan->sockfd, &tdm_api);
690 if (err) {
691 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Enable Failed");
692 return FTDM_FAIL;
693 }
694 #endif
695 }
696 break;
697 case FTDM_COMMAND_DISABLE_LOOP:
698 {
699 #ifdef WP_API_FEATURE_LOOP
700 err=sangoma_tdm_disable_loop(ftdmchan->sockfd, &tdm_api);
701 if (err) {
702 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Disable Failed");
703 return FTDM_FAIL;
704 }
705 #endif
706 }
707 break;
708 case FTDM_COMMAND_SET_INTERVAL:
709 {
710 err=sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, FTDM_COMMAND_OBJ_INT);
711 ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
712 }
713 break;
714 case FTDM_COMMAND_SET_CAS_BITS:
715 {
716 #ifdef LIBSANGOMA_VERSION
717 err = sangoma_tdm_write_rbs(ftdmchan->sockfd,&tdm_api, ftdmchan->physical_chan_id, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
718 #else
719 err = sangoma_tdm_write_rbs(ftdmchan->sockfd, &tdm_api, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
720 #endif
721 }
722 break;
723 case FTDM_COMMAND_GET_CAS_BITS:
724 {
725 #ifdef LIBSANGOMA_VERSION
726 unsigned char rbsbits;
727 err = sangoma_tdm_read_rbs(ftdmchan->sockfd, &tdm_api, ftdmchan->physical_chan_id, &rbsbits);
728 if (!err) {
729 FTDM_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
730 }
731 #else
732
733 FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
734 #endif
735 }
736 break;
737 case FTDM_COMMAND_SET_LINK_STATUS:
738 {
739 ftdm_channel_hw_link_status_t status = FTDM_COMMAND_OBJ_INT;
740 char sangoma_status = status == FTDM_HW_LINK_CONNECTED ? FE_CONNECTED : FE_DISCONNECTED;
741 err = sangoma_tdm_set_fe_status(ftdmchan->sockfd, &tdm_api, sangoma_status);
742 }
743 break;
744 case FTDM_COMMAND_GET_LINK_STATUS:
745 {
746 unsigned char sangoma_status = 0;
747 err = sangoma_tdm_get_fe_status(ftdmchan->sockfd, &tdm_api, &sangoma_status);
748 if (!err) {
749 FTDM_COMMAND_OBJ_INT = sangoma_status == FE_CONNECTED ? FTDM_HW_LINK_CONNECTED : FTDM_HW_LINK_DISCONNECTED;
750 }
751 }
752 break;
753 case FTDM_COMMAND_FLUSH_BUFFERS:
754 {
755 err = sangoma_flush_bufs(ftdmchan->sockfd, &tdm_api);
756 }
757 break;
758 case FTDM_COMMAND_FLUSH_RX_BUFFERS:
759 {
760 err = sangoma_flush_rx_bufs(ftdmchan->sockfd, &tdm_api);
761 }
762 break;
763 case FTDM_COMMAND_FLUSH_TX_BUFFERS:
764 {
765 err = sangoma_flush_tx_bufs(ftdmchan->sockfd, &tdm_api);
766 }
767 break;
768 case FTDM_COMMAND_FLUSH_IOSTATS:
769 {
770 err = sangoma_flush_stats(ftdmchan->sockfd, &tdm_api);
771 memset(&ftdmchan->iostats, 0, sizeof(ftdmchan->iostats));
772 }
773 break;
774 case FTDM_COMMAND_SET_RX_QUEUE_SIZE:
775 {
776 uint32_t queue_size = FTDM_COMMAND_OBJ_INT;
777 err = sangoma_set_rx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size);
778 }
779 break;
780 case FTDM_COMMAND_SET_TX_QUEUE_SIZE:
781 {
782 uint32_t queue_size = FTDM_COMMAND_OBJ_INT;
783 err = sangoma_set_tx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size);
784 }
785 break;
786 case FTDM_COMMAND_SET_POLARITY:
787 {
788 ftdm_polarity_t polarity = FTDM_COMMAND_OBJ_INT;
789 err = sangoma_tdm_set_polarity(ftdmchan->sockfd, &tdm_api, polarity);
790 if (!err) {
791 ftdmchan->polarity = polarity;
792 }
793 }
794 break;
795 default:
796 err = FTDM_NOTIMPL;
797 break;
798 };
799
800 if (err) {
801 int myerrno = errno;
802 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to execute command %d: %s\n", command, strerror(myerrno));
803 errno = myerrno;
804 return err;
805 }
806
807 return FTDM_SUCCESS;
808 }
809
810 static void wanpipe_write_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_tx_hdr_t *tx_stats)
811 {
812 ftdmchan->iostats.tx.errors = tx_stats->wp_api_tx_hdr_errors;
813 ftdmchan->iostats.tx.queue_size = tx_stats->wp_api_tx_hdr_max_queue_length;
814 ftdmchan->iostats.tx.queue_len = tx_stats->wp_api_tx_hdr_number_of_frames_in_queue;
815
816
817 if (ftdmchan->iostats.tx.queue_len >= ftdmchan->iostats.tx.queue_size) {
818 ftdm_set_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
819 } else if (ftdm_test_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL)){
820 ftdm_clear_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
821 }
822
823 if (ftdmchan->iostats.tx.idle_packets < tx_stats->wp_api_tx_hdr_tx_idle_packets) {
824
825
826 if (ftdmchan->iostats.tx.packets && FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
827 ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Tx idle changed from %d to %d\n",
828 ftdmchan->iostats.tx.idle_packets, tx_stats->wp_api_tx_hdr_tx_idle_packets);
829 }
830 ftdmchan->iostats.tx.idle_packets = tx_stats->wp_api_tx_hdr_tx_idle_packets;
831 }
832
833 if (!ftdmchan->iostats.tx.packets) {
834 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "First packet write stats: Tx queue len: %d, Tx queue size: %d, Tx idle: %d\n",
835 ftdmchan->iostats.tx.queue_len,
836 ftdmchan->iostats.tx.queue_size,
837 ftdmchan->iostats.tx.idle_packets);
838 }
839
840 ftdmchan->iostats.tx.packets++;
841 }
842
843 static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx_stats)
844 {
845 ftdmchan->iostats.rx.errors = rx_stats->wp_api_rx_hdr_errors;
846 ftdmchan->iostats.rx.queue_size = rx_stats->wp_api_rx_hdr_max_queue_length;
847 ftdmchan->iostats.rx.queue_len = rx_stats->wp_api_rx_hdr_number_of_frames_in_queue;
848
849 if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_ABORT_ERROR_BIT))) {
850 ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_ABORT);
851 } else {
852 ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_ABORT);
853 }
854
855 if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_DMA_ERROR_BIT))) {
856 ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_DMA);
857 } else {
858 ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_DMA);
859 }
860
861 if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_FIFO_ERROR_BIT))) {
862 ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FIFO);
863 } else {
864 ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FIFO);
865 }
866
867 if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_CRC_ERROR_BIT))) {
868 ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_CRC);
869 } else {
870 ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_CRC);
871 }
872
873 if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_FRAME_ERROR_BIT))) {
874 ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME);
875 } else {
876 ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME);
877 }
878
879 if (ftdmchan->iostats.rx.queue_len >= (0.8 * ftdmchan->iostats.rx.queue_size)) {
880 ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Rx Queue length exceeded 80% threshold (%d/%d)\n",
881 ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
882 ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES);
883 } else if (ftdm_test_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)){
884 ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Rx Queue length reduced 80% threshold (%d/%d)\n",
885 ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
886 ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES);
887 }
888
889 if (ftdmchan->iostats.rx.queue_len >= ftdmchan->iostats.rx.queue_size) {
890 ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Rx Queue Full (%d/%d)\n",
891 ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
892 ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
893 } else if (ftdm_test_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL)){
894 ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Rx Queue no longer full (%d/%d)\n",
895 ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
896 ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
897 }
898
899 if (!ftdmchan->iostats.rx.packets) {
900 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "First packet read stats: Rx queue len: %d, Rx queue size: %d\n",
901 ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
902 }
903
904 ftdmchan->iostats.rx.packets++;
905 }
906
907
908
909
910
911
912
913
914 static FIO_READ_FUNCTION(wanpipe_read)
915 {
916 int rx_len = 0;
917 int myerrno = 0;
918 wp_tdm_api_rx_hdr_t hdrframe;
919
920 memset(&hdrframe, 0, sizeof(hdrframe));
921
922 rx_len = sangoma_readmsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen, 0);
923 *datalen = rx_len;
924
925 if (rx_len == 0) {
926 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Read 0 bytes\n");
927 return FTDM_TIMEOUT;
928 }
929
930 if (rx_len < 0) {
931 myerrno = errno;
932 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
933 ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Failed to read from sangoma device: %s (%d)\n", strerror(errno), rx_len);
934 return FTDM_FAIL;
935 }
936
937 if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS)) {
938 wanpipe_read_stats(ftdmchan, &hdrframe);
939 }
940 return FTDM_SUCCESS;
941 }
942
943
944
945
946
947
948
949
950 static FIO_WRITE_FUNCTION(wanpipe_write)
951 {
952 int bsent = 0;
953 int err = 0;
954 wp_tdm_api_tx_hdr_t hdrframe;
955
956
957 memset(&hdrframe, 0, sizeof(hdrframe));
958 if (*datalen == 0) {
959 return FTDM_SUCCESS;
960 }
961
962 if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS) && !ftdmchan->iostats.tx.packets) {
963 wanpipe_tdm_api_t tdm_api;
964 memset(&tdm_api, 0, sizeof(tdm_api));
965
966 err = sangoma_flush_tx_bufs(ftdmchan->sockfd, &tdm_api);
967 if (err) {
968 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed to flush on first write\n");
969 }
970 }
971
972 bsent = sangoma_writemsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen),0);
973
974
975 if (bsent > 0) {
976 *datalen = bsent;
977 if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS)) {
978
979 if(!FTDM_SPAN_IS_BRI(ftdmchan->span)) {
980 wanpipe_write_stats(ftdmchan, &hdrframe);
981 }
982 }
983 return FTDM_SUCCESS;
984 }
985
986 return FTDM_FAIL;
987 }
988
989
990
991
992
993
994
995
996
997 static FIO_WAIT_FUNCTION(wanpipe_wait)
998 {
999 int32_t inflags = 0;
1000 int result;
1001
1002 if (*flags & FTDM_READ) {
1003 inflags |= POLLIN;
1004 }
1005
1006 if (*flags & FTDM_WRITE) {
1007 inflags |= POLLOUT;
1008 }
1009
1010 if (*flags & FTDM_EVENTS) {
1011 inflags |= POLLPRI;
1012 }
1013
1014 result = tdmv_api_wait_socket(ftdmchan, to, &inflags);
1015
1016 *flags = FTDM_NO_FLAGS;
1017
1018 if (result < 0){
1019 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
1020 return FTDM_FAIL;
1021 }
1022
1023 if (result == 0) {
1024 return FTDM_TIMEOUT;
1025 }
1026
1027 if (inflags & POLLIN) {
1028 *flags |= FTDM_READ;
1029 }
1030
1031 if (inflags & POLLOUT) {
1032 *flags |= FTDM_WRITE;
1033 }
1034
1035 if (inflags & POLLPRI) {
1036 *flags |= FTDM_EVENTS;
1037 }
1038
1039 return FTDM_SUCCESS;
1040 }
1041
1042
1043
1044
1045
1046
1047
1048 FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
1049 {
1050 #ifdef LIBSANGOMA_VERSION
1051 sangoma_status_t sangstatus;
1052 sangoma_wait_obj_t *pfds[FTDM_MAX_CHANNELS_SPAN] = { 0 };
1053 uint32_t inflags[FTDM_MAX_CHANNELS_SPAN];
1054 uint32_t outflags[FTDM_MAX_CHANNELS_SPAN];
1055 #else
1056 struct pollfd pfds[FTDM_MAX_CHANNELS_SPAN];
1057 #endif
1058 uint32_t i, j = 0, k = 0, l = 0;
1059 int r;
1060
1061 for(i = 1; i <= span->chan_count; i++) {
1062 ftdm_channel_t *ftdmchan = span->channels[i];
1063 uint32_t chan_events = 0;
1064
1065
1066
1067 if (poll_events) {
1068 if (poll_events[j] & FTDM_READ) {
1069 chan_events = SANG_WAIT_OBJ_HAS_INPUT;
1070 }
1071 if (poll_events[j] & FTDM_WRITE) {
1072 chan_events |= SANG_WAIT_OBJ_HAS_OUTPUT;
1073 }
1074 if (poll_events[j] & FTDM_EVENTS) {
1075 chan_events |= SANG_WAIT_OBJ_HAS_EVENTS;
1076 }
1077 } else {
1078 chan_events = SANG_WAIT_OBJ_HAS_EVENTS;
1079 }
1080
1081 #ifdef LIBSANGOMA_VERSION
1082 if (!ftdmchan->io_data) {
1083 continue;
1084 }
1085 pfds[j] = ftdmchan->io_data;
1086 inflags[j] = chan_events;
1087 #else
1088 memset(&pfds[j], 0, sizeof(pfds[j]));
1089 pfds[j].fd = span->channels[i]->sockfd;
1090 pfds[j].events = chan_events;
1091 #endif
1092
1093
1094 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
1095 l = 5;
1096 }
1097
1098 j++;
1099
1100 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
1101 l = 5;
1102 }
1103
1104 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING) && ftdm_current_time_in_ms() >= ftdmchan->ring_time) {
1105 wanpipe_tdm_api_t tdm_api;
1106 int err;
1107 memset(&tdm_api, 0, sizeof(tdm_api));
1108 if (ftdm_test_pflag(ftdmchan, WP_RINGING)) {
1109 err = sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
1110 if (err) {
1111 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
1112 ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_offhook failed\n");
1113 return FTDM_FAIL;
1114 }
1115 ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
1116 ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_off_ms;
1117 } else {
1118 err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
1119 if (err) {
1120 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
1121 ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_start failed\n");
1122 return FTDM_FAIL;
1123 }
1124 ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
1125 ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
1126 }
1127 }
1128 }
1129
1130 if (l) {
1131 ms = l;
1132 }
1133 #ifdef LIBSANGOMA_VERSION
1134 sangstatus = sangoma_waitfor_many(pfds, inflags, outflags, j, ms);
1135 if (SANG_STATUS_APIPOLL_TIMEOUT == sangstatus) {
1136 r = 0;
1137 } else if (SANG_STATUS_SUCCESS == sangstatus) {
1138 r = 1;
1139 } else {
1140 ftdm_log(FTDM_LOG_ERROR, "sangoma_waitfor_many failed: %d, %s\n", sangstatus, strerror(errno));
1141 r = -1;
1142 }
1143 #else
1144 r = poll(pfds, j, ms);
1145 #endif
1146
1147 if (r == 0) {
1148 return l ? FTDM_SUCCESS : FTDM_TIMEOUT;
1149 } else if (r < 0) {
1150 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
1151 return FTDM_FAIL;
1152 }
1153
1154 for(i = 1; i <= span->chan_count; i++) {
1155 ftdm_channel_t *ftdmchan = span->channels[i];
1156
1157 #ifdef LIBSANGOMA_VERSION
1158 if (outflags[i-1] & POLLPRI) {
1159 #else
1160 if (pfds[i-1].revents & POLLPRI) {
1161 #endif
1162 ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
1163 ftdmchan->last_event_time = ftdm_current_time_in_ms();
1164 k++;
1165 }
1166 }
1167
1168 return FTDM_SUCCESS;
1169 }
1170
1171
1172
1173
1174
1175
1176 static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
1177 {
1178 wanpipe_tdm_api_t tdm_api;
1179 unsigned int alarms = 0;
1180 int err;
1181
1182 memset(&tdm_api,0,sizeof(tdm_api));
1183
1184 #ifdef LIBSANGOMA_VERSION
1185 if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api, &alarms))) {
1186 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
1187 snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
1188 return FTDM_FAIL;
1189 }
1190 #else
1191 if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api)) < 0){
1192 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
1193 snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
1194 return FTDM_FAIL;
1195 }
1196 alarms = tdm_api.wp_tdm_cmd.fe_alarms;
1197 #endif
1198 #ifdef WIN32
1199
1200
1201
1202 if (FTDM_SPAN_IS_BRI(ftdmchan->span)) {
1203 if (alarms) {
1204 ftdmchan->alarm_flags |= FTDM_ALARM_RED;
1205 alarms = 0;
1206 }
1207 }
1208 #endif
1209
1210 ftdmchan->alarm_flags = FTDM_ALARM_NONE;
1211
1212 if (alarms & WAN_TE_BIT_ALARM_RED) {
1213 ftdmchan->alarm_flags |= FTDM_ALARM_RED;
1214 alarms &= ~WAN_TE_BIT_ALARM_RED;
1215 }
1216
1217
1218 if (alarms & WAN_TE_BIT_ALARM_AIS) {
1219 ftdmchan->alarm_flags |= FTDM_ALARM_BLUE;
1220 alarms &= ~WAN_TE_BIT_ALARM_AIS;
1221 }
1222
1223 if (alarms & WAN_TE_BIT_ALARM_RAI) {
1224 ftdmchan->alarm_flags |= FTDM_ALARM_YELLOW;
1225 alarms &= ~WAN_TE_BIT_ALARM_RAI;
1226 }
1227
1228 if (alarms) {
1229
1230 ftdm_log(FTDM_LOG_DEBUG, "Unmapped wanpipe alarms: %d\n", alarms);
1231 }
1232
1233 return FTDM_SUCCESS;
1234 }
1235
1236
1237
1238
1239
1240
1241
1242
1243 static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, wanpipe_tdm_api_t *tdm_api)
1244 {
1245 ftdm_status_t status = FTDM_SUCCESS;
1246
1247 switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type) {
1248 case WP_API_EVENT_LINK_STATUS:
1249 {
1250 switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
1251 case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
1252 *event_id = FTDM_OOB_ALARM_CLEAR;
1253 break;
1254 default:
1255 *event_id = FTDM_OOB_ALARM_TRAP;
1256 break;
1257 };
1258 }
1259 break;
1260
1261 case WP_API_EVENT_RXHOOK:
1262 {
1263 if (fchan->type == FTDM_CHAN_TYPE_FXS) {
1264 *event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_hook_state
1265 & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
1266 ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Got wanpipe %s\n", ftdm_oob_event2str(*event_id));
1267 if (*event_id == FTDM_OOB_OFFHOOK) {
1268 if (ftdm_test_flag(fchan, FTDM_CHANNEL_FLASH)) {
1269 ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
1270 ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
1271 *event_id = FTDM_OOB_FLASH;
1272 goto done;
1273 } else {
1274 ftdm_set_flag(fchan, FTDM_CHANNEL_WINK);
1275 }
1276 } else {
1277 if (ftdm_test_flag(fchan, FTDM_CHANNEL_WINK)) {
1278 ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
1279 ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
1280 *event_id = FTDM_OOB_WINK;
1281 ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Wink flag is set, delivering %s\n",
1282 ftdm_oob_event2str(*event_id));
1283 goto done;
1284 } else {
1285 ftdm_set_flag(fchan, FTDM_CHANNEL_FLASH);
1286 }
1287 }
1288 status = FTDM_BREAK;
1289 } else {
1290 ftdm_status_t status;
1291 wanpipe_tdm_api_t onhook_tdm_api;
1292 memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
1293 status = sangoma_tdm_txsig_onhook(fchan->sockfd, &onhook_tdm_api);
1294 if (status) {
1295 snprintf(fchan->last_error, sizeof(fchan->last_error), "ONHOOK Failed");
1296 return FTDM_FAIL;
1297 }
1298 *event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
1299 }
1300 }
1301 break;
1302 case WP_API_EVENT_RING_DETECT:
1303 {
1304 *event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
1305 }
1306 break;
1307
1308
1309
1310
1311
1312
1313
1314
1315 case WP_API_EVENT_RBS:
1316 {
1317 *event_id = FTDM_OOB_CAS_BITS_CHANGE;
1318 fchan->rx_cas_bits = wanpipe_swap_bits(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
1319 }
1320 break;
1321 case WP_API_EVENT_DTMF:
1322 {
1323 char tmp_dtmf[2] = { tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
1324 *event_id = FTDM_OOB_NOOP;
1325
1326 if (tmp_dtmf[0] == 'f') {
1327 ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
1328 break;
1329 }
1330
1331 if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
1332 ftdm_set_flag(fchan, FTDM_CHANNEL_MUTE);
1333 }
1334
1335 if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
1336 ftdm_clear_flag(fchan, FTDM_CHANNEL_MUTE);
1337 if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) {
1338 ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
1339 ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
1340 }
1341 }
1342 }
1343 break;
1344 case WP_API_EVENT_ALARM:
1345 {
1346 ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api->wp_tdm_cmd.event.wp_api_event_alarm);
1347 *event_id = FTDM_OOB_ALARM_TRAP;
1348 }
1349 break;
1350 case WP_API_EVENT_POLARITY_REVERSE:
1351 {
1352 ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Got polarity reverse\n");
1353 *event_id = FTDM_OOB_POLARITY_REVERSE;
1354 }
1355 break;
1356 default:
1357 {
1358 ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type);
1359 *event_id = FTDM_OOB_INVALID;
1360 }
1361 break;
1362 }
1363 done:
1364 return status;
1365 }
1366
1367
1368
1369
1370
1371
1372
1373 FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
1374 {
1375 ftdm_status_t status;
1376 ftdm_oob_event_t event_id;
1377 wanpipe_tdm_api_t tdm_api;
1378 ftdm_span_t *span = ftdmchan->span;
1379
1380 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
1381 ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
1382 }
1383
1384 memset(&tdm_api, 0, sizeof(tdm_api));
1385 status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
1386 if (status != FTDM_SUCCESS) {
1387 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
1388 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to read event from channel: %s\n", strerror(errno));
1389 return FTDM_FAIL;
1390 }
1391
1392 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
1393 status = wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api);
1394 if (status == FTDM_BREAK) {
1395 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Ignoring event for now\n");
1396 } else if (status != FTDM_SUCCESS) {
1397 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
1398 return FTDM_FAIL;
1399 } else {
1400 ftdmchan->last_event_time = 0;
1401 }
1402
1403 span->event_header.e_type = FTDM_EVENT_OOB;
1404 span->event_header.enum_id = event_id;
1405 span->event_header.channel = ftdmchan;
1406 *event = &span->event_header;
1407 return FTDM_SUCCESS;
1408 }
1409
1410
1411
1412
1413
1414
1415
1416 FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
1417 {
1418 uint32_t i,err;
1419 ftdm_oob_event_t event_id;
1420 for(i = 1; i <= span->chan_count; i++) {
1421
1422
1423 if (span->channels[i]->last_event_time && !ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
1424 ftdm_time_t diff = ftdm_current_time_in_ms() - span->channels[i]->last_event_time;
1425
1426 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
1427 if (diff > wp_globals.wink_ms) {
1428 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1429 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1430 ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
1431 event_id = FTDM_OOB_OFFHOOK;
1432 ftdm_log_chan(span->channels[i], FTDM_LOG_DEBUG, "Diff since last event = %llums, delivering %s now\n", diff, ftdm_oob_event2str(event_id));
1433 goto event;
1434 }
1435 }
1436
1437 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
1438 if (diff > wp_globals.flash_ms) {
1439 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1440 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1441 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
1442 event_id = FTDM_OOB_ONHOOK;
1443
1444 if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
1445 ftdm_channel_t *ftdmchan = span->channels[i];
1446 wanpipe_tdm_api_t tdm_api;
1447 memset(&tdm_api, 0, sizeof(tdm_api));
1448
1449 sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
1450 }
1451 ftdm_log_chan(span->channels[i], FTDM_LOG_DEBUG, "Diff since last event = %llums, delivering %s now\n", diff, ftdm_oob_event2str(event_id));
1452 goto event;
1453 }
1454 }
1455 }
1456 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
1457 ftdm_status_t status;
1458 wanpipe_tdm_api_t tdm_api;
1459 ftdm_channel_t *ftdmchan = span->channels[i];
1460 memset(&tdm_api, 0, sizeof(tdm_api));
1461 ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
1462
1463 err = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
1464 if (err != FTDM_SUCCESS) {
1465 ftdm_log_chan(span->channels[i], FTDM_LOG_ERROR, "read wanpipe event got error: %s\n", strerror(errno));
1466 return FTDM_FAIL;
1467 }
1468 ftdm_log_chan(span->channels[i], FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
1469
1470 ftdm_channel_lock(ftdmchan);
1471 status = wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api);
1472 ftdm_channel_unlock(ftdmchan);
1473
1474 if (status == FTDM_BREAK) {
1475 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring event for now\n");
1476 continue;
1477 } else if (status != FTDM_SUCCESS) {
1478 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
1479 return FTDM_FAIL;
1480 }
1481
1482 event:
1483
1484 span->channels[i]->last_event_time = 0;
1485 span->event_header.e_type = FTDM_EVENT_OOB;
1486 span->event_header.enum_id = event_id;
1487 span->event_header.channel = span->channels[i];
1488 *event = &span->event_header;
1489 return FTDM_SUCCESS;
1490 }
1491 }
1492 return FTDM_BREAK;
1493 }
1494
1495
1496
1497
1498
1499
1500 static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
1501 {
1502 #ifdef LIBSANGOMA_VERSION
1503 if (ftdmchan->io_data) {
1504 sangoma_wait_obj_t *sangoma_wait_obj;
1505 sangoma_wait_obj = ftdmchan->io_data;
1506 ftdmchan->io_data = NULL;
1507 sangoma_wait_obj_delete(&sangoma_wait_obj);
1508 }
1509 #endif
1510
1511 if (ftdmchan->sockfd != FTDM_INVALID_SOCKET) {
1512
1513
1514
1515
1516 if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
1517 wanpipe_tdm_api_t tdm_api;
1518 int err;
1519 memset(&tdm_api, 0, sizeof(tdm_api));
1520 err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api);
1521 if (err) {
1522 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed enabling Sangoma HW DTMF failed on channel destroy\n");
1523 }
1524 }
1525 sangoma_close(&ftdmchan->sockfd);
1526 }
1527
1528 return FTDM_SUCCESS;
1529 }
1530
1531
1532
1533
1534
1535
1536 static FIO_IO_LOAD_FUNCTION(wanpipe_init)
1537 {
1538 assert(fio != NULL);
1539 memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
1540
1541 wp_globals.codec_ms = 20;
1542 wp_globals.wink_ms = 150;
1543 wp_globals.flash_ms = 750;
1544 wp_globals.ring_on_ms = 2000;
1545 wp_globals.ring_off_ms = 4000;
1546 wanpipe_interface.name = "wanpipe";
1547 wanpipe_interface.configure_span = wanpipe_configure_span;
1548 wanpipe_interface.configure = wanpipe_configure;
1549 wanpipe_interface.open = wanpipe_open;
1550 wanpipe_interface.close = wanpipe_close;
1551 wanpipe_interface.command = wanpipe_command;
1552 wanpipe_interface.wait = wanpipe_wait;
1553 wanpipe_interface.read = wanpipe_read;
1554 wanpipe_interface.write = wanpipe_write;
1555 wanpipe_interface.poll_event = wanpipe_poll_event;
1556 wanpipe_interface.next_event = wanpipe_span_next_event;
1557 wanpipe_interface.channel_next_event = wanpipe_channel_next_event;
1558 wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
1559 wanpipe_interface.get_alarms = wanpipe_get_alarms;
1560 *fio = &wanpipe_interface;
1561
1562 return FTDM_SUCCESS;
1563 }
1564
1565
1566
1567
1568
1569 static FIO_IO_UNLOAD_FUNCTION(wanpipe_destroy)
1570 {
1571 memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
1572 return FTDM_SUCCESS;
1573 }
1574
1575
1576
1577
1578 EX_DECLARE_DATA ftdm_module_t ftdm_module = {
1579 "wanpipe",
1580 wanpipe_init,
1581 wanpipe_destroy,
1582 };
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593