root/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tdmv_api_wait_socket
  2. tdmv_api_open_span_chan
  3. __tdmv_api_open_span_chan
  4. wanpipe_swap_bits
  5. wp_open_range
  6. FIO_CONFIGURE_FUNCTION
  7. FIO_CONFIGURE_SPAN_FUNCTION
  8. FIO_OPEN_FUNCTION
  9. FIO_CLOSE_FUNCTION
  10. FIO_COMMAND_FUNCTION
  11. wanpipe_write_stats
  12. wanpipe_read_stats
  13. FIO_READ_FUNCTION
  14. FIO_WRITE_FUNCTION
  15. FIO_WAIT_FUNCTION
  16. FIO_SPAN_POLL_EVENT_FUNCTION
  17. FIO_GET_ALARMS_FUNCTION
  18. wanpipe_channel_process_event
  19. FIO_CHANNEL_NEXT_EVENT_FUNCTION
  20. FIO_SPAN_NEXT_EVENT_FUNCTION
  21. FIO_CHANNEL_DESTROY_FUNCTION
  22. FIO_IO_LOAD_FUNCTION
  23. FIO_IO_UNLOAD_FUNCTION

   1 /*
   2  * Copyright (c) 2007, Anthony Minessale II
   3  * All rights reserved.
   4  * 
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 
   9  * * Redistributions of source code must retain the above copyright
  10  * notice, this list of conditions and the following disclaimer.
  11  * 
  12  * * Redistributions in binary form must reproduce the above copyright
  13  * notice, this list of conditions and the following disclaimer in the
  14  * documentation and/or other materials provided with the distribution.
  15  * 
  16  * * Neither the name of the original author; nor the names of any contributors
  17  * may be used to endorse or promote products derived from this software
  18  * without specific prior written permission.
  19  * 
  20  * 
  21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
  25  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  *
  33  * Contributors: 
  34  *
  35  * Moises Silva <moy@sangoma.com>
  36  * David Yat Sin <davidy@sangoma.com>
  37  * Nenad Corbic <ncorbic@sangoma.com>
  38  * Arnaldo Pereira <arnaldo@sangoma.com>
  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 /*! Backward compatible defines - current code is all using the old names*/ 
  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 /*! Starting with libsangoma 3 we can use the new libsangoma waitable API, the poor souls of those using a release where LIBSANGOMA version
  74  * is defined but the version is not higher or equal to 3.0.0 will be forced to upgrade
  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  * \brief Wanpipe flags
  84  */
  85 typedef enum {
  86         WP_RINGING = (1 << 0)
  87 } wp_flag_t;
  88 
  89 /**
  90  * \brief Wanpipe globals
  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 /* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
 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  * \brief Poll for event on a wanpipe socket
 108  * \param fd Wanpipe socket descriptor
 109  * \param timeout Time to wait for event
 110  * \param flags Sangoma event flags
 111  * \return -1 on failure, wanpipe event flags on success
 112  *
 113  * a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog
 114  * so we can have one analong handler thread that will deal with all the idle analog channels for events
 115  * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
 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; /* ideally should be the number of file descriptors with something to read */
 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  * \brief Opens a sangoma channel socket (TDM API)
 165  * \param span Span number
 166  * \param chan Channel number
 167  * \return 0 on success, wanpipe error code on failure
 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  * \brief Inverts bit string
 185  * \param cas_bits CAS bit string
 186  * \return Swapped bits
 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  * \brief Initialises a range of wanpipe channels
 208  * \param span FreeTDM span
 209  * \param spanno Wanpipe span number
 210  * \param start Initial wanpipe channel number
 211  * \param end Final wanpipe channel number
 212  * \param type FreeTDM channel type
 213  * \param name FreeTDM span name
 214  * \param number FreeTDM span number
 215  * \param cas_bits CAS bits
 216  * \return number of spans configured
 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                         /* we need SANGOMA_DEVICE_WAIT_OBJ_SIG and not SANGOMA_DEVICE_WAIT_OBJ alone because we need to call 
 253                          * sangoma_wait_obj_sig to wake up any I/O waiters when closing the channel (typically on ftdm shutdown)
 254                          * this adds an extra pair of file descriptors to the waitable object
 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                                         /* we had problems of on-hook/off-hook detection due to how ring trip events were handled
 314                                          * if this fails, I believe we will still work ok as long as we dont handle them incorrectly */
 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                 /* Enable FLASH/Wink Events */
 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                                 /* this should probably be done for old libsangoma but I am not sure if the API is available and I'm lazy to check,
 336                                    The poll rate is hard coded to 100 per second (done in the driver, is the max rate of polling allowed by wanpipe)
 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                                  * With wanpipe 3.4.4.2 I get failure even though the events are enabled, /var/log/messages said:
 347                                  * wanpipe4: WARNING: Event type 9 is already pending!
 348                                  * wanpipe4: Failed to add new fe event 09 ch_map=FFFFFFFF!
 349                                  * may be we should not send an error until that is fixed in the driver
 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                                 /* probably done by the driver but lets write defensive code this time */
 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  * \brief Process configuration variable for a Wanpipe profile
 380  * \param category Wanpipe profile name
 381  * \param var Variable name
 382  * \param val Variable value
 383  * \param lineno Line number from configuration file
 384  * \return Success
 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  * \brief Initialises an freetdm Wanpipe span from a configuration string
 434  * \param span FreeTDM span
 435  * \param str Configuration string
 436  * \param type FreeTDM span type
 437  * \param name FreeTDM span name
 438  * \param number FreeTDM span number
 439  * \return Success or failure
 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  * \brief Opens Wanpipe channel
 512  * \param ftdmchan Channel to open
 513  * \return Success or failure
 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  * \brief Closes Wanpipe channel
 543  * \param ftdmchan Channel to close
 544  * \return Success
 545  */
 546 static FIO_CLOSE_FUNCTION(wanpipe_close)
 547 {
 548 #ifdef LIBSANGOMA_VERSION
 549         sangoma_wait_obj_t *waitobj = ftdmchan->io_data;
 550         /* kick any I/O waiters */
 551         sangoma_wait_obj_signal(waitobj);
 552 #endif
 553         return FTDM_SUCCESS;
 554 }
 555 
 556 /**
 557  * \brief Executes an FreeTDM command on a Wanpipe channel
 558  * \param ftdmchan Channel to execute command on
 559  * \param command FreeTDM command to execute
 560  * \param obj Object (unused)
 561  * \return Success or failure
 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                                 /* Hardware echo canceller already enabled */
 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                                 /* Hardware echo canceller already disabled */  
 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                         // does sangoma_tdm_read_rbs is available here?
 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         /* we don't test for 80% full in tx since is typically full for voice channels, should we test tx 80% full for D-channels? */
 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                 /* HDLC channels do not always transmit, so its ok for drivers to fill with idle
 825                  * also do not report idle warning when we just started transmitting */
 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  * \brief Reads data from a Wanpipe channel
 909  * \param ftdmchan Channel to read from
 910  * \param data Data buffer
 911  * \param datalen Size of data buffer
 912  * \return Success, failure or timeout
 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  * \brief Writes data to a Wanpipe channel
 945  * \param ftdmchan Channel to write to
 946  * \param data Data buffer
 947  * \param datalen Size of data buffer
 948  * \return Success or failure
 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         /* Do we even need the headerframe here? on windows, we don't even pass it to the driver */
 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                 /* if this is the first write ever, flush the tx first to have clean stats */
 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         /* should we be checking if bsent == *datalen here? */
 975         if (bsent > 0) {
 976                 *datalen = bsent;
 977                 if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS)) {
 978                         /* BRI cards do not support TX queues for now */
 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  * \brief Waits for an event on a Wanpipe channel
 991  * \param ftdmchan Channel to open
 992  * \param flags Type of event to wait for
 993  * \param to Time to wait (in ms)
 994  * \return Success, failure or timeout
 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  * \brief Checks for events on a Wanpipe span
1044  * \param span Span to check for events
1045  * \param ms Time to wait for event
1046  * \return Success if event is waiting or failure if not
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                 /* translate events from ftdm to libsnagoma. if the user don't specify which events to poll the
1066                  * channel for, we just use SANG_WAIT_OBJ_HAS_EVENTS */
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; /* should never happen but happens when shutting down */
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                 /* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
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; /* hopefully we never need how many changed -_- */
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         /* when k is 0 it might be that an async wanpipe device signal was delivered */ 
1168         return FTDM_SUCCESS;
1169 }
1170 
1171 /**
1172  * \brief Gets alarms from a Wanpipe Channel
1173  * \param ftdmchan Channel to get alarms from
1174  * \return Success or failure
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         /* Temporary fix: in the current trunk of libsangoma, for BRI,
1200                 WAN_TE_BIT_ALARM_RED bit is set if the card is in disconnected state, but this has
1201                 not been ported to Windows-libsangoma yet */
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                 /* FIXME: investigate what else does the driver report */
1230                 ftdm_log(FTDM_LOG_DEBUG, "Unmapped wanpipe alarms: %d\n", alarms);
1231         }
1232 
1233         return FTDM_SUCCESS;
1234 }
1235 
1236 /**
1237  * \brief Process an event in a channel and set it's OOB event id. The channel must be locked.
1238  * \param fchan Channel in which event occured
1239  * \param event_id Pointer where we save the OOB event id
1240  * \param tdm_api Wanpipe tdm struct that contain the event
1241  * \return FTDM_SUCCESS or FTDM_FAIL
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                 disabled this ones when configuring, we don't need them, do we?
1309         case WP_API_EVENT_RING_TRIP_DETECT:
1310                 {
1311                         *event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
1312                 }
1313                 break;
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  * \brief Retrieves an event from a wanpipe channel
1369  * \param channel Channel to retrieve event from
1370  * \param event FreeTDM event to return
1371  * \return Success or failure
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  * \brief Retrieves an event from a wanpipe span
1412  * \param span Span to retrieve event from
1413  * \param event FreeTDM event to return
1414  * \return Success or failure
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                 /* as a hack for wink/flash detection, wanpipe_poll_event overrides the timeout parameter
1422                  * to force the user to call this function each 5ms or so to detect the timeout of our wink/flash */
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                         /* XX printf("%u %u %u\n", diff, (unsigned)ftdm_current_time_in_ms(), (unsigned)span->channels[i]->last_event_time); */
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  * \brief Destroys a Wanpipe Channel
1497  * \param ftdmchan Channel to destroy
1498  * \return Success
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                 /* enable HW DTMF. As odd as it seems. Why enable when the channel is being destroyed and won't be used anymore?
1513                  * because that way we can transfer the DTMF state back to the driver, if we're being restarted we will set again
1514                  * the FEATURE_DTMF flag and use HW DTMF, if we don't enable here, then on module restart we won't see
1515                  * HW DTMF available and will use software */
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  * \brief Loads wanpipe IO module
1533  * \param fio FreeTDM IO interface
1534  * \return Success
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  * \brief Unloads wanpipe IO module
1567  * \return Success
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  * \brief FreeTDM wanpipe IO module definition
1577  */
1578 EX_DECLARE_DATA ftdm_module_t ftdm_module = { 
1579         "wanpipe",
1580         wanpipe_init,
1581         wanpipe_destroy,
1582 };
1583 
1584 /* For Emacs:
1585  * Local Variables:
1586  * mode:c
1587  * indent-tabs-mode:t
1588  * tab-width:4
1589  * c-basic-offset:4
1590  * End:
1591  * For VIM:
1592  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 
1593  */

/* [<][>][^][v][top][bottom][index][help] */