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. FIO_READ_FUNCTION
  12. FIO_WRITE_FUNCTION
  13. FIO_WAIT_FUNCTION
  14. FIO_SPAN_POLL_EVENT_FUNCTION
  15. FIO_GET_ALARMS_FUNCTION
  16. FIO_SPAN_NEXT_EVENT_FUNCTION
  17. FIO_CHANNEL_DESTROY_FUNCTION
  18. FIO_IO_LOAD_FUNCTION
  19. 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  *
  39  */
  40 
  41 #ifdef __sun
  42 #include <unistd.h>
  43 #include <stropts.h>
  44 #endif
  45 #include "private/ftdm_core.h"
  46 #ifndef __WINDOWS__
  47 #include <poll.h>
  48 #include <sys/socket.h>
  49 #endif
  50 #include "libsangoma.h"
  51 
  52 #if defined(__WINDOWS__)
  53 /*! Backward compatible defines - current code is all using the old names*/ 
  54 #define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan
  55 #define sangoma_open_tdmapi_span sangoma_open_api_span
  56 #define sangoma_open_tdmapi_ctrl sangoma_open_api_ctrl
  57 #define sangoma_tdm_get_fe_status sangoma_get_fe_status
  58 #define sangoma_socket_close sangoma_close
  59 #define sangoma_tdm_get_hw_coding sangoma_get_hw_coding
  60 #define sangoma_tdm_set_fe_status sangoma_set_fe_status
  61 #define sangoma_tdm_get_link_status sangoma_get_link_status
  62 #define sangoma_tdm_flush_bufs sangoma_flush_bufs
  63 #define sangoma_tdm_cmd_exec sangoma_cmd_exec
  64 #define sangoma_tdm_read_event sangoma_read_event
  65 #define sangoma_readmsg_tdm sangoma_readmsg
  66 #define sangoma_readmsg_socket sangoma_readmsg
  67 #define sangoma_sendmsg_socket sangoma_writemsg
  68 #define sangoma_writemsg_tdm sangoma_writemsg
  69 #define sangoma_create_socket_intr sangoma_open_api_span_chan
  70 #endif
  71 
  72 /*! Starting with libsangoma 3 we can use the new libsangoma waitable API, the poor souls of those using a release where LIBSANGOMA version
  73  * is defined but the version is not higher or equal to 3.0.0 will be forced to upgrade
  74  * */
  75 #ifdef LIBSANGOMA_VERSION 
  76 #if LIBSANGOMA_VERSION_CODE < LIBSANGOMA_VERSION(3,0,0)
  77 #undef LIBSANGOMA_VERSION
  78 #endif
  79 #endif
  80 
  81 /**
  82  * \brief Wanpipe flags
  83  */
  84 typedef enum {
  85         WP_RINGING = (1 << 0)
  86 } wp_flag_t;
  87 
  88 /**
  89  * \brief Wanpipe globals
  90  */
  91 static struct {
  92         uint32_t codec_ms;
  93         uint32_t wink_ms;
  94         uint32_t flash_ms;
  95         uint32_t ring_on_ms;
  96         uint32_t ring_off_ms;
  97 } wp_globals;
  98 
  99 /* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
 100 
 101 FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
 102 FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
 103 
 104 /**
 105  * \brief Poll for event on a wanpipe socket
 106  * \param fd Wanpipe socket descriptor
 107  * \param timeout Time to wait for event
 108  * \param flags Sangoma event flags
 109  * \return -1 on failure, wanpipe event flags on success
 110  *
 111  * a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog
 112  * so we can have one analong handler thread that will deal with all the idle analog channels for events
 113  * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
 114  */
 115 static __inline__ int tdmv_api_wait_socket(ftdm_channel_t *ftdmchan, int timeout, int *flags)
 116 {
 117         
 118 #ifdef LIBSANGOMA_VERSION
 119         int err;
 120     uint32_t inflags = *flags;
 121     uint32_t outflags = 0;
 122         sangoma_wait_obj_t *sangoma_wait_obj = ftdmchan->mod_data;
 123 
 124         err = sangoma_waitfor(sangoma_wait_obj, inflags, &outflags, timeout);
 125         *flags = 0;
 126     if (err == SANG_STATUS_SUCCESS) {
 127         *flags = outflags;
 128         err = 1; /* ideally should be the number of file descriptors with something to read */
 129     }
 130     if (err == SANG_STATUS_APIPOLL_TIMEOUT) {
 131         err = 0;
 132     }
 133     return err;
 134 #else
 135         struct pollfd pfds[1];
 136     int res;
 137 
 138     memset(&pfds[0], 0, sizeof(pfds[0]));
 139     pfds[0].fd = ftdmchan->sockfd;
 140     pfds[0].events = *flags;
 141     res = poll(pfds, 1, timeout);
 142         *flags = 0;
 143 
 144         if (pfds[0].revents & POLLERR) {
 145                 res = -1;
 146         }
 147 
 148         if (res > 0) {
 149                 *flags = pfds[0].revents;
 150         }
 151 
 152     return res;
 153 #endif
 154         
 155 }
 156 
 157 /**
 158  * \brief Opens a sangoma channel socket (TDM API)
 159  * \param span Span number
 160  * \param chan Channel number
 161  * \return 0 on success, wanpipe error code on failure
 162  */
 163 static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan) 
 164 {
 165         return sangoma_open_tdmapi_span_chan(span, chan);
 166 }
 167 
 168 #ifdef LIBSANGOMA_VERSION
 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 #endif
 174 
 175 static ftdm_io_interface_t wanpipe_interface;
 176 
 177 /**
 178  * \brief Inverts bit string
 179  * \param cas_bits CAS bit string
 180  * \return Swapped bits
 181  */
 182 static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
 183 {
 184         unsigned char swapped_bits = 0x0;
 185         if (cas_bits & 0x8) {
 186                 swapped_bits |= 0x1;
 187         }
 188         if (cas_bits & 0x4) {
 189                 swapped_bits |= 0x2;
 190         }
 191         if (cas_bits & 0x2) {
 192                 swapped_bits |= 0x4;
 193         }
 194         if (cas_bits & 0x1) {
 195                 swapped_bits |= 0x8;
 196         }
 197         return swapped_bits;
 198 }
 199 
 200 /**
 201  * \brief Initialises a range of wanpipe channels
 202  * \param span FreeTDM span
 203  * \param spanno Wanpipe span number
 204  * \param start Initial wanpipe channel number
 205  * \param end Final wanpipe channel number
 206  * \param type FreeTDM channel type
 207  * \param name FreeTDM span name
 208  * \param number FreeTDM span number
 209  * \param cas_bits CAS bits
 210  * \return number of spans configured
 211  */
 212 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)
 213 {
 214         unsigned configured = 0, x;
 215 #ifdef LIBSANGOMA_VERSION
 216         sangoma_status_t sangstatus;
 217         sangoma_wait_obj_t *sangoma_wait_obj;
 218 #endif
 219 
 220         if (type == FTDM_CHAN_TYPE_CAS) {
 221                 ftdm_log(FTDM_LOG_DEBUG, "Configuring Wanpipe CAS channels with abcd == 0x%X\n", cas_bits);
 222         }       
 223         for(x = start; x < end; x++) {
 224                 ftdm_channel_t *chan;
 225                 ftdm_socket_t sockfd = FTDM_INVALID_SOCKET;
 226                 const char *dtmf = "none";
 227                 if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == FTDM_TRUNK_T1 && x == 24) {
 228 #ifdef LIBSANGOMA_VERSION
 229                         sockfd = __tdmv_api_open_span_chan(spanno, x);
 230 #else
 231                         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);
 232 #endif
 233                 } else {
 234                         sockfd = tdmv_api_open_span_chan(spanno, x);
 235                 }
 236 
 237                 if (sockfd == FTDM_INVALID_SOCKET) {
 238                         ftdm_log(FTDM_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
 239                         continue;
 240                 }
 241                 
 242                 if (ftdm_span_add_channel(span, sockfd, type, &chan) == FTDM_SUCCESS) {
 243                         wanpipe_tdm_api_t tdm_api;
 244                         memset(&tdm_api, 0, sizeof(tdm_api));
 245 #ifdef LIBSANGOMA_VERSION
 246                         /* we need SANGOMA_DEVICE_WAIT_OBJ_SIG and not SANGOMA_DEVICE_WAIT_OBJ alone because we need to call 
 247                          * sangoma_wait_obj_sig to wake up any I/O waiters when closing the channel (typically on ftdm shutdown)
 248                          * this adds an extra pair of file descriptors to the waitable object
 249                          * */
 250                         sangstatus = sangoma_wait_obj_create(&sangoma_wait_obj, sockfd, SANGOMA_DEVICE_WAIT_OBJ_SIG);
 251                         if (sangstatus != SANG_STATUS_SUCCESS) {
 252                                 ftdm_log(FTDM_LOG_ERROR, "failure create waitable object for s%dc%d\n", spanno, x);
 253                                 continue;
 254                         }
 255                         chan->mod_data = sangoma_wait_obj;
 256 #endif
 257                         
 258                         chan->physical_span_id = spanno;
 259                         chan->physical_chan_id = x;
 260                         chan->rate = 8000;
 261                         
 262                         if (type == FTDM_CHAN_TYPE_FXS 
 263                         || type == FTDM_CHAN_TYPE_FXO 
 264                         || type == FTDM_CHAN_TYPE_CAS
 265                         || type == FTDM_CHAN_TYPE_B) {
 266                                 int err;
 267                                 
 268                                 dtmf = "software";
 269 
 270                                 err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
 271 
 272                                 if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
 273                                         chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
 274                                 } else {
 275                                         chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
 276                                 }
 277 
 278                                 err = sangoma_tdm_get_hw_dtmf(chan->sockfd, &tdm_api);
 279                                 if (err > 0) {
 280                                         ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_DTMF_DETECT);
 281                                         dtmf = "hardware";
 282                                 }
 283 
 284                                 err = sangoma_tdm_get_hw_ec(chan->sockfd, &tdm_api);
 285                                 if (err > 0) {
 286                                         ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC);
 287                                 }
 288                                 
 289 #ifdef WP_API_FEATURE_HWEC_PERSIST
 290                                 err = sangoma_tdm_get_hwec_persist_status(chan->sockfd, &tdm_api);
 291                                 if (err == 0) {
 292                                         ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE);
 293                                 }
 294 #else
 295                                 if (span->trunk_type ==  FTDM_TRUNK_BRI || span->trunk_type ==  FTDM_TRUNK_BRI_PTMP) {
 296                                         ftdm_log(FTDM_LOG_WARNING, "WP_API_FEATURE_HWEC_PERSIST feature is not supported \
 297                                                          with your version of libsangoma, you should update your Wanpipe drivers\n");
 298 
 299                                 }
 300 #endif
 301 
 302                         }
 303 
 304 #ifdef LIBSANGOMA_VERSION
 305                         if (type == FTDM_CHAN_TYPE_FXS) {
 306                                 if (sangoma_tdm_disable_ring_trip_detect_events(chan->sockfd, &tdm_api)) {
 307                                         /* we had problems of on-hook/off-hook detection due to how ring trip events were handled
 308                                          * if this fails, I believe we will still work ok as long as we dont handle them incorrectly */
 309                                         ftdm_log(FTDM_LOG_WARNING, "Failed to disable ring trip events in channel s%dc%d\n", spanno, x);
 310                                 }
 311                         }
 312 #endif
 313 #if 0
 314             if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
 315                 /* Enable FLASH/Wink Events */
 316                 int err=sangoma_set_rm_rxflashtime(chan->sockfd, &tdm_api, wp_globals.flash_ms);
 317                 if (err == 0) {
 318                                 ftdm_log(FTDM_LOG_ERROR, "flash enabled s%dc%d\n", spanno, x);
 319                 } else {
 320                                 ftdm_log(FTDM_LOG_ERROR, "flash disabled s%dc%d\n", spanno, x);
 321                 }
 322             }
 323 #endif
 324 
 325                         if (type == FTDM_CHAN_TYPE_CAS || type == FTDM_CHAN_TYPE_EM) {
 326 #ifdef LIBSANGOMA_VERSION
 327                                 sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id, wanpipe_swap_bits(cas_bits));
 328 
 329                                 /* this should probably be done for old libsangoma but I am not sure if the API is available and I'm lazy to check,
 330                                    The poll rate is hard coded to 100 per second (done in the driver, is the max rate of polling allowed by wanpipe)
 331                                  */
 332                                 if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
 333                                         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);
 334                                         continue;
 335                                 }
 336                                 /* probably done by the driver but lets write defensive code this time */
 337                                 sangoma_flush_bufs(chan->sockfd, &tdm_api);
 338 #else
 339                                 /* 
 340                                  * With wanpipe 3.4.4.2 I get failure even though the events are enabled, /var/log/messages said:
 341                                  * wanpipe4: WARNING: Event type 9 is already pending!
 342                                  * wanpipe4: Failed to add new fe event 09 ch_map=FFFFFFFF!
 343                                  * may be we should not send an error until that is fixed in the driver
 344                                  */
 345                                 if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
 346                                         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);
 347                                 }
 348                                 /* probably done by the driver but lets write defensive code this time */
 349                                 sangoma_tdm_flush_bufs(chan->sockfd, &tdm_api);
 350                                 sangoma_tdm_write_rbs(chan->sockfd,&tdm_api, wanpipe_swap_bits(cas_bits));
 351 #endif
 352                         }
 353                         
 354                         if (!ftdm_strlen_zero(name)) {
 355                                 ftdm_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
 356                         }
 357 
 358                         if (!ftdm_strlen_zero(number)) {
 359                                 ftdm_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
 360                         }
 361                         configured++;
 362                         ftdm_log_chan(chan, FTDM_LOG_INFO, "configured wanpipe device s%dc%d as FreeTDM channel %d:%d fd:%d DTMF: %s\n",
 363                                 spanno, x, chan->span_id, chan->chan_id, sockfd, dtmf);
 364 
 365                 } else {
 366                         ftdm_log(FTDM_LOG_ERROR, "ftdm_span_add_channel failed for wanpipe span %d channel %d\n", spanno, x);
 367                 }
 368         }
 369         
 370         return configured;
 371 }
 372 
 373 /**
 374  * \brief Process configuration variable for a Wanpipe profile
 375  * \param category Wanpipe profile name
 376  * \param var Variable name
 377  * \param val Variable value
 378  * \param lineno Line number from configuration file
 379  * \return Success
 380  */
 381 static FIO_CONFIGURE_FUNCTION(wanpipe_configure)
 382 {
 383         int num;
 384 
 385         if (!strcasecmp(category, "defaults")) {
 386                 if (!strcasecmp(var, "codec_ms")) {
 387                         num = atoi(val);
 388                         if (num < 10 || num > 60) {
 389                                 ftdm_log(FTDM_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
 390                         } else {
 391                                 wp_globals.codec_ms = num;
 392                         }
 393                 } else if (!strcasecmp(var, "wink_ms")) {
 394                         num = atoi(val);
 395                         if (num < 50 || num > 3000) {
 396                                 ftdm_log(FTDM_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
 397                         } else {
 398                                 wp_globals.wink_ms = num;
 399                         }
 400                 } else if (!strcasecmp(var, "flash_ms")) {
 401                         num = atoi(val);
 402                         if (num < 50 || num > 3000) {
 403                                 ftdm_log(FTDM_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
 404                         } else {
 405                                 wp_globals.flash_ms = num;
 406                         }
 407                 } else if (!strcasecmp(var, "ring_on_ms")) {
 408                         num = atoi(val);
 409                         if (num < 500 || num > 5000) {
 410                                 ftdm_log(FTDM_LOG_WARNING, "invalid ring_on_ms at line %d (valid range 500 to 5000)\n", lineno);
 411                         } else {
 412                                 wp_globals.ring_on_ms = num;
 413                         }
 414                 } else if (!strcasecmp(var, "ring_off_ms")) {
 415                         num = atoi(val);
 416                         if (num < 500 || num > 5000) {
 417                                 ftdm_log(FTDM_LOG_WARNING, "invalid ring_off_ms at line %d (valid range 500 to 5000)\n", lineno);
 418                         } else {
 419                                 wp_globals.ring_off_ms = num;
 420                         }
 421                 }
 422         }
 423 
 424         return FTDM_SUCCESS;
 425 }
 426 
 427 /**
 428  * \brief Initialises an freetdm Wanpipe span from a configuration string
 429  * \param span FreeTDM span
 430  * \param str Configuration string
 431  * \param type FreeTDM span type
 432  * \param name FreeTDM span name
 433  * \param number FreeTDM span number
 434  * \return Success or failure
 435  */
 436 static FIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
 437 {
 438         int items, i;
 439         char *mydata, *item_list[10];
 440         char *sp, *ch, *mx;
 441         unsigned char cas_bits = 0;
 442         int channo;
 443         int spanno;
 444         int top = 0;
 445         unsigned configured = 0;
 446 
 447         assert(str != NULL);
 448         
 449 
 450         mydata = ftdm_strdup(str);
 451         assert(mydata != NULL);
 452 
 453 
 454         items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
 455 
 456         for(i = 0; i < items; i++) {
 457                 sp = item_list[i];
 458                 if ((ch = strchr(sp, ':'))) {
 459                         *ch++ = '\0';
 460                 }
 461 
 462                 if (!(sp && ch)) {
 463                         ftdm_log(FTDM_LOG_ERROR, "No valid wanpipe span and channel was specified\n");
 464                         continue;
 465                 }
 466 
 467                 channo = atoi(ch);
 468                 spanno = atoi(sp);
 469 
 470                 if (channo < 0) {
 471                         ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
 472                         continue;
 473                 }
 474 
 475                 if (spanno < 0) {
 476                         ftdm_log(FTDM_LOG_ERROR, "Invalid span number %d\n", channo);
 477                         continue;
 478                 }
 479                 
 480                 if ((mx = strchr(ch, '-'))) {
 481                         mx++;
 482                         top = atoi(mx) + 1;
 483                 } else {
 484                         top = channo + 1;
 485                 }
 486                 
 487                 
 488                 if (top < 0) {
 489                         ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
 490                         continue;
 491                 }
 492                 if (FTDM_CHAN_TYPE_CAS == type && ftdm_config_get_cas_bits(ch, &cas_bits)) {
 493                         ftdm_log(FTDM_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
 494                         continue;
 495                 }
 496                 configured += wp_open_range(span, spanno, channo, top, type, name, number, cas_bits);
 497 
 498         }
 499         
 500         ftdm_safe_free(mydata);
 501 
 502         return configured;
 503 }
 504 
 505 /**
 506  * \brief Opens Wanpipe channel
 507  * \param ftdmchan Channel to open
 508  * \return Success or failure
 509  */
 510 static FIO_OPEN_FUNCTION(wanpipe_open) 
 511 {
 512 
 513         wanpipe_tdm_api_t tdm_api;
 514 
 515         memset(&tdm_api,0,sizeof(tdm_api));
 516         sangoma_tdm_flush_bufs(ftdmchan->sockfd, &tdm_api);
 517 #ifdef LIBSANGOMA_VERSION
 518         sangoma_flush_event_bufs(ftdmchan->sockfd, &tdm_api);
 519 #endif
 520 
 521         if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) {
 522                 ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE;
 523         } else {
 524                 ftdmchan->effective_codec = ftdmchan->native_codec;
 525                 
 526                 sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, wp_globals.codec_ms);
 527 
 528                 ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
 529                 ftdmchan->effective_interval = ftdmchan->native_interval = wp_globals.codec_ms;
 530                 ftdmchan->packet_len = ftdmchan->native_interval * 8;
 531         }
 532 
 533         return FTDM_SUCCESS;
 534 }
 535 
 536 /**
 537  * \brief Closes Wanpipe channel
 538  * \param ftdmchan Channel to close
 539  * \return Success
 540  */
 541 static FIO_CLOSE_FUNCTION(wanpipe_close)
 542 {
 543 #ifdef LIBSANGOMA_VERSION
 544         sangoma_wait_obj_t *waitobj = ftdmchan->mod_data;
 545         /* kick any I/O waiters */
 546         sangoma_wait_obj_signal(waitobj);
 547 #endif
 548         return FTDM_SUCCESS;
 549 }
 550 
 551 /**
 552  * \brief Executes an FreeTDM command on a Wanpipe channel
 553  * \param ftdmchan Channel to execute command on
 554  * \param command FreeTDM command to execute
 555  * \param obj Object (unused)
 556  * \return Success or failure
 557  */
 558 static FIO_COMMAND_FUNCTION(wanpipe_command)
 559 {
 560         wanpipe_tdm_api_t tdm_api;
 561         int err = 0;
 562 
 563         memset(&tdm_api, 0, sizeof(tdm_api));
 564 
 565         switch(command) {
 566         case FTDM_COMMAND_OFFHOOK:
 567                 {
 568                         err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
 569                         if (err) {
 570                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed");
 571                                 return FTDM_FAIL;
 572                         }
 573                         ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
 574                 }
 575                 break;
 576         case FTDM_COMMAND_ONHOOK:
 577                 {
 578                         err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
 579                         if (err) {
 580                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
 581                                 return FTDM_FAIL;
 582                         }
 583                         ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
 584                 }
 585                 break;
 586         case FTDM_COMMAND_GENERATE_RING_ON:
 587                 {
 588                         err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
 589                         if (err) {
 590                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
 591                                 return FTDM_FAIL;
 592                         }
 593                         ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
 594                         ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
 595                         ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
 596                 }
 597                 break;
 598         case FTDM_COMMAND_GENERATE_RING_OFF:
 599                 {
 600                         err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
 601                         if (err) {
 602                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
 603                                 return FTDM_FAIL;
 604                         }
 605                         ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
 606                         ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
 607                 }
 608                 break;
 609         case FTDM_COMMAND_GET_INTERVAL:
 610                 {
 611                         err=sangoma_tdm_get_usr_period(ftdmchan->sockfd, &tdm_api);
 612                         if (err > 0 ) {
 613                                 FTDM_COMMAND_OBJ_INT = err;
 614                                 err=0;
 615                         }
 616                 }
 617                 break;
 618         case FTDM_COMMAND_ENABLE_ECHOCANCEL:
 619                 {
 620 #ifdef WP_API_FEATURE_EC_CHAN_STAT
 621                         err=sangoma_tdm_get_hwec_chan_status(ftdmchan->sockfd, &tdm_api);
 622                         if (err > 0) {
 623                                 /* Hardware echo canceller already enabled */
 624                                 err = 0;
 625                                 break;
 626                         }
 627 #endif
 628                         err=sangoma_tdm_enable_hwec(ftdmchan->sockfd, &tdm_api);
 629                         if (err) {
 630                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed");
 631                                 return FTDM_FAIL;
 632                         }
 633                 }
 634                 break;
 635         case FTDM_COMMAND_DISABLE_ECHOCANCEL:
 636                 {
 637 #ifdef WP_API_FEATURE_EC_CHAN_STAT
 638                         err=sangoma_tdm_get_hwec_chan_status(ftdmchan->sockfd, &tdm_api);
 639                         if (!err) {
 640                                 /* Hardware echo canceller already disabled */  
 641                                 break;
 642                         }
 643 #endif          
 644                         err=sangoma_tdm_disable_hwec(ftdmchan->sockfd, &tdm_api);
 645                         if (err) {
 646                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed");
 647                                 return FTDM_FAIL;
 648                         }
 649                 }
 650                 break;
 651         case FTDM_COMMAND_ENABLE_DTMF_DETECT:
 652                 {
 653 #ifdef WP_API_FEATURE_DTMF_EVENTS
 654                         err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api);
 655                         if (err) {
 656                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Enabling of Sangoma HW DTMF failed\n");
 657                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Enable Failed");
 658                                 return FTDM_FAIL;
 659                         }
 660                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled DTMF events\n");
 661 #else
 662                         return FTDM_NOTIMPL;
 663 #endif
 664                 }
 665                 break;
 666         case FTDM_COMMAND_DISABLE_DTMF_DETECT:
 667                 {
 668 #ifdef WP_API_FEATURE_DTMF_EVENTS
 669                         err = sangoma_tdm_disable_dtmf_events(ftdmchan->sockfd, &tdm_api);
 670                         if (err) {
 671                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Disabling of Sangoma HW DTMF failed\n");
 672                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Disable Failed");
 673                                 return FTDM_FAIL;
 674                         }
 675                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Disabled DTMF events\n");
 676 #else
 677                         return FTDM_NOTIMPL;
 678 #endif
 679                 }
 680                 break;
 681         case FTDM_COMMAND_ENABLE_LOOP:
 682                 {
 683 #ifdef WP_API_FEATURE_LOOP
 684                 err=sangoma_tdm_enable_loop(ftdmchan->sockfd, &tdm_api);
 685                         if (err) {
 686                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Enable Failed");
 687                                 return FTDM_FAIL;
 688                         }
 689 #endif          
 690                 }
 691                 break;
 692         case FTDM_COMMAND_DISABLE_LOOP:
 693                 {
 694 #ifdef WP_API_FEATURE_LOOP
 695                 err=sangoma_tdm_disable_loop(ftdmchan->sockfd, &tdm_api);
 696                         if (err) {
 697                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Disable Failed");
 698                                 return FTDM_FAIL;
 699                         }
 700 #endif   
 701                 }
 702                 break;
 703         case FTDM_COMMAND_SET_INTERVAL: 
 704                 {
 705                         err=sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, FTDM_COMMAND_OBJ_INT);
 706                         ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
 707                 }
 708                 break;
 709         case FTDM_COMMAND_SET_CAS_BITS:
 710                 {
 711 #ifdef LIBSANGOMA_VERSION
 712                         err = sangoma_tdm_write_rbs(ftdmchan->sockfd,&tdm_api, ftdmchan->physical_chan_id, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
 713 #else
 714                         err = sangoma_tdm_write_rbs(ftdmchan->sockfd, &tdm_api, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
 715 #endif
 716                 }
 717                 break;
 718         case FTDM_COMMAND_GET_CAS_BITS:
 719                 {
 720 #ifdef LIBSANGOMA_VERSION
 721                         unsigned char rbsbits;
 722                         err = sangoma_tdm_read_rbs(ftdmchan->sockfd, &tdm_api, ftdmchan->physical_chan_id, &rbsbits);
 723                         if (!err) {
 724                                 FTDM_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
 725                         }
 726 #else
 727                         // does sangoma_tdm_read_rbs is available here?
 728                         FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
 729 #endif
 730                 }
 731                 break;
 732         case FTDM_COMMAND_SET_LINK_STATUS:
 733                 {
 734                         ftdm_channel_hw_link_status_t status = FTDM_COMMAND_OBJ_INT;
 735                         char sangoma_status = status == FTDM_HW_LINK_CONNECTED ? FE_CONNECTED : FE_DISCONNECTED;
 736                         err = sangoma_tdm_set_fe_status(ftdmchan->sockfd, &tdm_api, sangoma_status);
 737                 }
 738                 break;
 739         case FTDM_COMMAND_GET_LINK_STATUS:
 740                 {
 741                         unsigned char sangoma_status = 0;
 742                         err = sangoma_tdm_get_fe_status(ftdmchan->sockfd, &tdm_api, &sangoma_status);
 743                         if (!err) {
 744                                 FTDM_COMMAND_OBJ_INT = sangoma_status == FE_CONNECTED ? FTDM_HW_LINK_CONNECTED : FTDM_HW_LINK_DISCONNECTED;
 745                         }
 746                 }
 747                 break;
 748         default:
 749                 break;
 750         };
 751 
 752         if (err) {
 753                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
 754                 return FTDM_FAIL;
 755         }
 756 
 757 
 758         return FTDM_SUCCESS;
 759 }
 760 
 761 /**
 762  * \brief Reads data from a Wanpipe channel
 763  * \param ftdmchan Channel to read from
 764  * \param data Data buffer
 765  * \param datalen Size of data buffer
 766  * \return Success, failure or timeout
 767  */
 768 static FIO_READ_FUNCTION(wanpipe_read)
 769 {
 770         int rx_len = 0;
 771         int myerrno = 0;
 772         wp_tdm_api_rx_hdr_t hdrframe;
 773 
 774         memset(&hdrframe, 0, sizeof(hdrframe));
 775 
 776         rx_len = sangoma_readmsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen, 0);
 777         *datalen = rx_len;
 778 
 779         if (rx_len == 0) {
 780                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Read 0 bytes\n");
 781                 return FTDM_TIMEOUT;
 782         }
 783 
 784         if (rx_len < 0) {
 785                 myerrno = errno;
 786                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
 787                 ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Failed to read from sangoma device: %s (%d)\n", strerror(errno), rx_len);
 788                 return FTDM_FAIL;
 789         } 
 790 
 791 
 792         return FTDM_SUCCESS;
 793 }
 794 
 795 /**
 796  * \brief Writes data to a Wanpipe channel
 797  * \param ftdmchan Channel to write to
 798  * \param data Data buffer
 799  * \param datalen Size of data buffer
 800  * \return Success or failure
 801  */
 802 static FIO_WRITE_FUNCTION(wanpipe_write)
 803 {
 804         int bsent;
 805         wp_tdm_api_tx_hdr_t hdrframe;
 806 
 807         /* Do we even need the headerframe here? on windows, we don't even pass it to the driver */
 808         memset(&hdrframe, 0, sizeof(hdrframe));
 809         if (*datalen == 0) {
 810                 return FTDM_SUCCESS;
 811         }
 812         bsent = sangoma_writemsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen),0);
 813 
 814         /* should we be checking if bsent == *datalen here? */
 815         if (bsent > 0) {
 816                 *datalen = bsent;
 817                 return FTDM_SUCCESS;
 818         }
 819 
 820         return FTDM_FAIL;
 821 }
 822 
 823 /**
 824  * \brief Waits for an event on a Wanpipe channel
 825  * \param ftdmchan Channel to open
 826  * \param flags Type of event to wait for
 827  * \param to Time to wait (in ms)
 828  * \return Success, failure or timeout
 829  */
 830 
 831 static FIO_WAIT_FUNCTION(wanpipe_wait)
 832 {
 833         int32_t inflags = 0;
 834         int result;
 835 
 836         if (*flags & FTDM_READ) {
 837                 inflags |= POLLIN;
 838         }
 839 
 840         if (*flags & FTDM_WRITE) {
 841                 inflags |= POLLOUT;
 842         }
 843 
 844         if (*flags & FTDM_EVENTS) {
 845                 inflags |= POLLPRI;
 846         }
 847 
 848         result = tdmv_api_wait_socket(ftdmchan, to, &inflags);
 849 
 850         *flags = FTDM_NO_FLAGS;
 851 
 852         if (result < 0){
 853                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
 854                 return FTDM_FAIL;
 855         }
 856 
 857         if (result == 0) {
 858                 return FTDM_TIMEOUT;
 859         }
 860 
 861         if (inflags & POLLIN) {
 862                 *flags |= FTDM_READ;
 863         }
 864 
 865         if (inflags & POLLOUT) {
 866                 *flags |= FTDM_WRITE;
 867         }
 868 
 869         if (inflags & POLLPRI) {
 870                 *flags |= FTDM_EVENTS;
 871         }
 872 
 873         return FTDM_SUCCESS;
 874 }
 875 
 876 /**
 877  * \brief Checks for events on a Wanpipe span
 878  * \param span Span to check for events
 879  * \param ms Time to wait for event
 880  * \return Success if event is waiting or failure if not
 881  */
 882 FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
 883 {
 884 #ifdef LIBSANGOMA_VERSION
 885         sangoma_status_t sangstatus;
 886         sangoma_wait_obj_t *pfds[FTDM_MAX_CHANNELS_SPAN] = { 0 };
 887         uint32_t inflags[FTDM_MAX_CHANNELS_SPAN];
 888         uint32_t outflags[FTDM_MAX_CHANNELS_SPAN];
 889 #else
 890         struct pollfd pfds[FTDM_MAX_CHANNELS_SPAN];
 891 #endif
 892         uint32_t i, j = 0, k = 0, l = 0;
 893         int r;
 894         
 895         for(i = 1; i <= span->chan_count; i++) {
 896                 ftdm_channel_t *ftdmchan = span->channels[i];
 897 #ifdef LIBSANGOMA_VERSION
 898                 if (!ftdmchan->mod_data) {
 899                         continue; /* should never happen but happens when shutting down */
 900                 }
 901                 pfds[j] = ftdmchan->mod_data;
 902                 inflags[j] = POLLPRI;
 903 #else
 904                 memset(&pfds[j], 0, sizeof(pfds[j]));
 905                 pfds[j].fd = span->channels[i]->sockfd;
 906                 pfds[j].events = POLLPRI;
 907 #endif
 908 
 909                 /* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
 910                 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
 911                         l = 5;
 912                 }
 913 
 914                 j++;
 915 
 916                 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
 917                         l = 5;
 918                 }
 919 
 920                 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING) && ftdm_current_time_in_ms() >= ftdmchan->ring_time) {
 921                         wanpipe_tdm_api_t tdm_api;
 922                         int err;
 923                         memset(&tdm_api, 0, sizeof(tdm_api));
 924                         if (ftdm_test_pflag(ftdmchan, WP_RINGING)) {
 925                                 err = sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
 926                                 if (err) {
 927                                         snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
 928                                         ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_offhook failed\n");
 929                                         return FTDM_FAIL;
 930                                 }
 931                                 ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
 932                                 ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_off_ms;
 933                         } else {
 934                                 err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
 935                                 if (err) {
 936                                         snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
 937                                         ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_start failed\n");
 938                                         return FTDM_FAIL;
 939                                 }
 940                                 ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
 941                                 ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
 942                         }
 943                 }
 944         }
 945 
 946         if (l) {
 947                 ms = l;
 948         }
 949 #ifdef LIBSANGOMA_VERSION
 950         sangstatus = sangoma_waitfor_many(pfds, inflags, outflags, j, ms);
 951         if (SANG_STATUS_APIPOLL_TIMEOUT == sangstatus) {
 952                 r = 0;
 953         } else if (SANG_STATUS_SUCCESS == sangstatus) {
 954                 r = 1; /* hopefully we never need how many changed -_- */
 955         } else {
 956                 ftdm_log(FTDM_LOG_ERROR, "sangoma_waitfor_many failed: %d, %s\n", sangstatus, strerror(errno));
 957                 r = -1;
 958         }
 959 #else
 960         r = poll(pfds, j, ms);
 961 #endif
 962         
 963         if (r == 0) {
 964                 return l ? FTDM_SUCCESS : FTDM_TIMEOUT;
 965         } else if (r < 0) {
 966                 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
 967                 return FTDM_FAIL;
 968         }
 969         
 970         for(i = 1; i <= span->chan_count; i++) {
 971                 ftdm_channel_t *ftdmchan = span->channels[i];
 972 
 973 #ifdef LIBSANGOMA_VERSION
 974                 if (outflags[i-1] & POLLPRI) {
 975 #else
 976                 if (pfds[i-1].revents & POLLPRI) {
 977 #endif
 978                         ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
 979                         ftdmchan->last_event_time = ftdm_current_time_in_ms();
 980                         k++;
 981                 }
 982         }
 983         /* when k is 0 it might be that an async wanpipe device signal was delivered */ 
 984         return FTDM_SUCCESS;
 985 }
 986 
 987 /**
 988  * \brief Gets alarms from a Wanpipe Channel
 989  * \param ftdmchan Channel to get alarms from
 990  * \return Success or failure
 991  */
 992 static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
 993 {
 994         wanpipe_tdm_api_t tdm_api;
 995         unsigned int alarms = 0;
 996         int err;
 997 
 998         memset(&tdm_api,0,sizeof(tdm_api));
 999 
1000 #ifdef LIBSANGOMA_VERSION
1001         if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api, &alarms))) {
1002                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
1003                 snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
1004                 return FTDM_FAIL;               
1005         }
1006 #else
1007         if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api)) < 0){
1008                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
1009                 snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
1010                 return FTDM_FAIL;               
1011         }
1012         alarms = tdm_api.wp_tdm_cmd.fe_alarms;
1013 #endif
1014         ftdmchan->alarm_flags = FTDM_ALARM_NONE;
1015 
1016         if (alarms & WAN_TE_BIT_ALARM_RED) {
1017                 ftdmchan->alarm_flags |= FTDM_ALARM_RED;
1018                 alarms &= ~WAN_TE_BIT_ALARM_RED;
1019         }
1020 
1021         if (alarms & WAN_TE_BIT_ALARM_AIS) {
1022                 ftdmchan->alarm_flags |= FTDM_ALARM_BLUE;
1023                 alarms &= ~WAN_TE_BIT_ALARM_AIS;
1024         }
1025 
1026         if (alarms & WAN_TE_BIT_ALARM_RAI) {
1027                 ftdmchan->alarm_flags |= FTDM_ALARM_YELLOW;
1028                 alarms &= ~WAN_TE_BIT_ALARM_RAI;
1029         }
1030 
1031         if (alarms) {
1032                 /* FIXME: investigate what else does the driver report */
1033                 ftdm_log(FTDM_LOG_DEBUG, "Unmapped wanpipe alarms: %d\n", alarms);
1034         }
1035 
1036         return FTDM_SUCCESS;
1037 }
1038 
1039 /**
1040  * \brief Retrieves an event from a wanpipe span
1041  * \param span Span to retrieve event from
1042  * \param event FreeTDM event to return
1043  * \return Success or failure
1044  */
1045 FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
1046 {
1047         uint32_t i,err;
1048         ftdm_oob_event_t event_id;
1049         for(i = 1; i <= span->chan_count; i++) {
1050                 if (span->channels[i]->last_event_time && !ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
1051                         uint32_t diff = (uint32_t)(ftdm_current_time_in_ms() - span->channels[i]->last_event_time);
1052                         /* XX printf("%u %u %u\n", diff, (unsigned)ftdm_current_time_in_ms(), (unsigned)span->channels[i]->last_event_time); */
1053                         if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
1054                                 if (diff > wp_globals.wink_ms) {
1055                                         ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1056                                         ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1057                                         ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
1058                                         event_id = FTDM_OOB_OFFHOOK;
1059                                         goto event;
1060                                 }
1061                         }
1062 
1063                         if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
1064                                 if (diff > wp_globals.flash_ms) {
1065                                         ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1066                                         ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1067                                         ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
1068                                         event_id = FTDM_OOB_ONHOOK;
1069 
1070                                         if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
1071                                                 ftdm_channel_t *ftdmchan = span->channels[i];
1072                                                 wanpipe_tdm_api_t tdm_api;
1073                                                 memset(&tdm_api, 0, sizeof(tdm_api));
1074 
1075                                                 sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
1076                                         }
1077                                         goto event;
1078                                 }
1079                         }
1080                 } 
1081                 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
1082                         wanpipe_tdm_api_t tdm_api;
1083                         ftdm_channel_t *ftdmchan = span->channels[i];
1084                         memset(&tdm_api, 0, sizeof(tdm_api));
1085                         ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
1086 
1087                         err = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
1088                         if (err != FTDM_SUCCESS) {
1089                                 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
1090                                 return FTDM_FAIL;
1091                         }
1092                         
1093                         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);
1094                         switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
1095 
1096                         case WP_TDMAPI_EVENT_LINK_STATUS:
1097                                 {
1098                                         switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
1099                                         case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
1100                                                 event_id = FTDM_OOB_ALARM_CLEAR;
1101                                                 break;
1102                                         default:
1103                                                 event_id = FTDM_OOB_ALARM_TRAP;
1104                                                 break;
1105                                         };
1106                                 }
1107                                 break;
1108 
1109                         case WP_TDMAPI_EVENT_RXHOOK:
1110                                 {
1111                                         if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS) {
1112                                                 event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
1113                                                 if (event_id == FTDM_OOB_OFFHOOK) {
1114                                                         if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
1115                                                                 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1116                                                                 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1117                                                                 event_id = FTDM_OOB_FLASH;
1118                                                                 goto event;
1119                                                         } else {
1120                                                                 ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1121                                                         }
1122                                                 } else {
1123                                                         if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
1124                                                                 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1125                                                                 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1126                                                                 event_id = FTDM_OOB_WINK;
1127                                                                 goto event;
1128                                                         } else {
1129                                                                 ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1130                                                         }
1131                                                 }                                       
1132                                                 continue;
1133                                         } else {
1134                                                 int err;
1135                                                 ftdm_channel_t *ftdmchan = span->channels[i];
1136                                                 err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
1137                                                 if (err) {
1138                                                         snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
1139                                                         return FTDM_FAIL;
1140                                                 }
1141                                                 event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP; 
1142                                         }
1143                                 }
1144                                 break;
1145                         case WP_TDMAPI_EVENT_RING_DETECT:
1146                                 {
1147                                         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;
1148                                 }
1149                                 break;
1150                                 /*
1151                                 disabled this ones when configuring, we don't need them, do we?
1152                         case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
1153                                 {
1154                                         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;
1155                                 }
1156                                 break;
1157                                 */
1158                         case WP_TDMAPI_EVENT_RBS:
1159                                 {
1160                                         event_id = FTDM_OOB_CAS_BITS_CHANGE;
1161                                         span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
1162                                 }
1163                                 break;
1164                         case WP_TDMAPI_EVENT_DTMF:
1165                                 {
1166                                         char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
1167                                         event_id = FTDM_OOB_NOOP;
1168 
1169                                         if (tmp_dtmf[0] == 'f') {
1170                                                 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
1171                                                 break;
1172                                         }
1173 
1174                                         if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
1175                                                 ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
1176                                         }
1177 
1178                                         if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
1179                                                 ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
1180                                                 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
1181                                                         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
1182                                                         ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
1183                                                 }
1184                                         } 
1185                                 }
1186                                 break;
1187                         case WP_TDMAPI_EVENT_ALARM:
1188                                 {
1189                                         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
1190                                         event_id = FTDM_OOB_ALARM_TRAP;
1191                                 }
1192                                 break;
1193                         default:
1194                                 {
1195                                         ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
1196                                         event_id = FTDM_OOB_INVALID;
1197                                 }
1198                                 break;
1199                         }
1200 
1201                 event:
1202 
1203                         span->channels[i]->last_event_time = 0;
1204                         span->event_header.e_type = FTDM_EVENT_OOB;
1205                         span->event_header.enum_id = event_id;
1206                         span->event_header.channel = span->channels[i];
1207                         *event = &span->event_header;
1208                         return FTDM_SUCCESS;
1209                 }
1210         }
1211 
1212         return FTDM_FAIL;
1213         
1214 }
1215 
1216 /**
1217  * \brief Destroys a Wanpipe Channel
1218  * \param ftdmchan Channel to destroy
1219  * \return Success
1220  */
1221 static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
1222 {
1223 #ifdef LIBSANGOMA_VERSION
1224         if (ftdmchan->mod_data) {
1225                 sangoma_wait_obj_t *sangoma_wait_obj;
1226                 sangoma_wait_obj = ftdmchan->mod_data;
1227                 ftdmchan->mod_data = NULL;
1228                 sangoma_wait_obj_delete(&sangoma_wait_obj);
1229         }
1230 #endif
1231 
1232         if (ftdmchan->sockfd != FTDM_INVALID_SOCKET) {
1233                 /* enable HW DTMF. As odd as it seems. Why enable when the channel is being destroyed and won't be used anymore?
1234                  * because that way we can transfer the DTMF state back to the driver, if we're being restarted we will set again
1235                  * the FEATURE_DTMF flag and use HW DTMF, if we don't enable here, then on module restart we won't see
1236                  * HW DTMF available and will use software */
1237                 if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
1238                         wanpipe_tdm_api_t tdm_api;
1239                         int err;
1240                         memset(&tdm_api, 0, sizeof(tdm_api));
1241                         err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api);
1242                         if (err) {
1243                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed enabling Sangoma HW DTMF failed on channel destroy\n");
1244                         }
1245                 }
1246                 sangoma_close(&ftdmchan->sockfd);
1247         }
1248 
1249         return FTDM_SUCCESS;
1250 }
1251 
1252 /**
1253  * \brief Loads wanpipe IO module
1254  * \param fio FreeTDM IO interface
1255  * \return Success
1256  */
1257 static FIO_IO_LOAD_FUNCTION(wanpipe_init)
1258 {
1259         assert(fio != NULL);
1260         memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
1261 
1262         wp_globals.codec_ms = 20;
1263         wp_globals.wink_ms = 150;
1264         wp_globals.flash_ms = 750;
1265         wp_globals.ring_on_ms = 2000;
1266         wp_globals.ring_off_ms = 4000;
1267         wanpipe_interface.name = "wanpipe";
1268         wanpipe_interface.configure_span = wanpipe_configure_span;
1269         wanpipe_interface.configure = wanpipe_configure;
1270         wanpipe_interface.open = wanpipe_open;
1271         wanpipe_interface.close = wanpipe_close;
1272         wanpipe_interface.command = wanpipe_command;
1273         wanpipe_interface.wait = wanpipe_wait;
1274         wanpipe_interface.read = wanpipe_read;
1275         wanpipe_interface.write = wanpipe_write;
1276         wanpipe_interface.poll_event = wanpipe_poll_event;
1277         wanpipe_interface.next_event = wanpipe_next_event;
1278         wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
1279         wanpipe_interface.get_alarms = wanpipe_get_alarms;
1280         *fio = &wanpipe_interface;
1281 
1282         return FTDM_SUCCESS;
1283 }
1284 
1285 /**
1286  * \brief Unloads wanpipe IO module
1287  * \return Success
1288  */
1289 static FIO_IO_UNLOAD_FUNCTION(wanpipe_destroy)
1290 {
1291         memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
1292         return FTDM_SUCCESS;
1293 }
1294 
1295 /**
1296  * \brief FreeTDM wanpipe IO module definition
1297  */
1298 EX_DECLARE_DATA ftdm_module_t ftdm_module = { 
1299         "wanpipe",
1300         wanpipe_init,
1301         wanpipe_destroy,
1302 };
1303 
1304 /* For Emacs:
1305  * Local Variables:
1306  * mode:c
1307  * indent-tabs-mode:t
1308  * tab-width:4
1309  * c-basic-offset:4
1310  * End:
1311  * For VIM:
1312  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 
1313  */

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