libsangoma  1
sample.cpp
Go to the documentation of this file.
1 /*******************************************************************************/
35 #include "sangoma_port.h"
36 #include "sangoma_port_configurator.h"
37 #include "sangoma_interface.h"
38 
39 #if defined(__LINUX__)
40 # include "sample_linux_compat.h"
41 #else
42 # include <conio.h>
43 #endif
44 
45 #include <iostream>
46 #include <string>
47 
48 using namespace std;
49 
50 #ifndef MAX_PATH
51 #define MAX_PATH 100
52 #endif
53 
54 
55 /*****************************************************************
56  * Global Variables
57  *****************************************************************/
58 
59 wp_program_settings_t program_settings;
60 callback_functions_t callback_functions;
61 
62 
63 /*****************************************************************
64  * Prototypes & Defines
65  *****************************************************************/
66 
67 static int got_rx_data(void *sang_if_ptr, void *rxhdr, void *rx_data);
68 static void got_tdm_api_event(void *sang_if_ptr, void *event_data);
69 #if USE_WP_LOGGER
70 static void got_logger_event(void *sang_if_ptr, wp_logger_event_t *logger_event);
71 #endif
72 
73 
74 #if USE_STELEPHONY_API
75 //Sangoma Telephony API (Stelephony.dll) provides the following telephony services:
76 //1. FSK Caller ID detection for Analog FXO.
77 //2. Software DTMF detection.
78 //3. Q931 decoding
79 static void FSKCallerIDEvent(void *callback_context, char * Name, char * CallerNumber, char * CalledNumber, char * DateTime);
80 static void DTMFEvent(void *callback_context, long Key);
81 static void Q931Event(void *callback_context, stelephony_q931_event *pQ931Event);
82 static void FSKCallerIDTransmit (void *callback_context, void* buffer);
83 static void SwDtmfTransmit (void *callback_context, void* buffer);
84 #endif
85 
86 //critical section for synchronizing access to 'stdout' between the threads
87 CRITICAL_SECTION PrintCriticalSection;
88 //critical section for TDM events
89 CRITICAL_SECTION TdmEventCriticalSection;
90 
91 /*****************************************************************
92  * Debugging Macros
93  *****************************************************************/
94 
95 #define DBG_MAIN if(1)printf
96 #define ERR_MAIN printf("%s():line:%d:Error:", __FUNCTION__, __LINE__);printf
97 #define INFO_MAIN if(1)printf
98 
99 #define MAIN_FUNC() if(1)printf("%s():line:%d\n", __FUNCTION__, __LINE__)
100 
101 static int set_port_configuration();
102 
111 sangoma_interface* init(int wanpipe_number, int interface_number)
112 {
113  sangoma_interface *sang_if = NULL;
114  DBG_MAIN("%s()\n", __FUNCTION__);
115 
116  if(program_settings.use_ctrl_dev == 1){
117  sang_if = new sangoma_api_ctrl_dev();
118  }else if(program_settings.use_logger_dev == 1){
119  sang_if = new sangoma_api_logger_dev();
120  }else{
121  sang_if = new sangoma_interface(wanpipe_number, interface_number);
122  }
123 
124  if(sang_if->init(&callback_functions)){
125  delete sang_if;
126  return NULL;
127  }
128 
129  DBG_MAIN("init(): OK\n");
130  return sang_if;
131 }
132 
140 {
141  DBG_MAIN("cleanup()\n");
142  if(sang_if){
143  delete sang_if;
144  }
145 }
146 
154 {
155  DBG_MAIN("start()\n");
156  return sang_if->run();
157 }
158 
165 void stop(sangoma_interface *sang_if)
166 {
167  DBG_MAIN("stop()\n");
168  sang_if->stop();
169 }
170 
177 void PrintRxData(wp_api_hdr_t *hdr, void *pdata)
178 {
179  unsigned short datlen;
180  unsigned char * data;
181  static unsigned int rx_counter = 0;
182 
183  //NOTE: if running in BitStream mode, there will be TOO MUCH to print
184  datlen = hdr->data_length;
185  data = (unsigned char*)pdata;
186 
187  rx_counter++;
188  if(program_settings.silent){
189  if((rx_counter % 1000) == 0){
190  INFO_MAIN("Rx counter: %d, Rx datlen: %d\n", rx_counter, datlen);
191 #if 1
192  INFO_MAIN("Timestamp: Seconds: %d, Microseconds: %d\n",
193  hdr->time_stamp_sec, hdr->time_stamp_usec);
194 #endif
195  }
196  return;
197  }else{
198  INFO_MAIN("Rx counter: %d, Rx datlen: %d. Data:\n", rx_counter, datlen);
199  }
200 
201 #if 1
202  for(int ln = 0; ln < datlen; ln++){
203  if((ln % 20 == 0)){
204  if(ln){
205  INFO_MAIN("\n");
206  }
207  INFO_MAIN("%04d ", ln/20);
208  }
209  INFO_MAIN("%02X ", data[ln]);
210  }
211  INFO_MAIN("\n");
212 #endif
213 }
214 
215 
226 static int got_rx_data(void *sang_if_ptr, void *rxhdr, void *rx_data)
227 {
228  sangoma_interface *sang_if = (sangoma_interface*)sang_if_ptr;
229 
230 #if 0
231 #ifdef __LINUX__
232  static struct timeval tv_start;
233  static int elapsed_b4=0;
234  struct timeval last;
235  int elapsed;
236 
237  last=tv_start;
238  gettimeofday(&tv_start, NULL);
239  elapsed = abs(elapsed_b4);
240  elapsed_b4 = abs((((last.tv_sec * 1000) + last.tv_usec / 1000) - ((tv_start.tv_sec * 1000) + tv_start.tv_usec / 1000)));
241  if (abs(elapsed - elapsed_b4) > 1) {
242  INFO_MAIN("wanpipe%d: Elapsed %i %i diff=%i\n", program_settings.wanpipe_number, elapsed,elapsed_b4,abs(elapsed-elapsed_b4));
243  }
244 #endif
245 #endif
246  //Do something with data received from Sangoma interface.
247  //Fore example, transimit back everything what was received:
248 
249  if(program_settings.Rx_to_Tx_loopback == 1){
250  sang_if->transmit((wp_api_hdr_t*)rxhdr, rx_data);
251  }
252 
253  EnterCriticalSection(&PrintCriticalSection);
254  PrintRxData((wp_api_hdr_t*)rxhdr, rx_data);
255  LeaveCriticalSection(&PrintCriticalSection);
256  return 0;
257 }
258 
273 static void got_tdm_api_event(void *sang_if_ptr, void *event_data)
274 {
275  sangoma_interface *sang_if = (sangoma_interface *)sang_if_ptr;
276  wp_api_event_t *wp_tdm_api_event = (wp_api_event_t *)event_data;
277  wan_time_t wan_time;
278  char *timestamp_str;
279 
280  EnterCriticalSection(&TdmEventCriticalSection);
281 
282  /* Windows: wan_time is 64bit, time_stamp_sec is 32bit
283  * Linux: wan_time and time_stamp_sec is 32bit */
284  wan_time = wp_tdm_api_event->time_stamp_sec;
285  timestamp_str = sangoma_ctime( &wan_time );
286 
287  /* Display Logger Event Timestamp as UNIX-style Date string. */
288  /*DBG_MAIN("Time and Date:\t\t%s\n", (timestamp_str == NULL ? "Invalid Timestamp" : timestamp_str));*/
289 
290  DBG_MAIN("%s(): Span: %d, Channel: %d (Seconds:%u, Microseconds:%u)\n", __FUNCTION__,
291  wp_tdm_api_event->wp_api_event_span, wp_tdm_api_event->wp_api_event_channel,
292  wp_tdm_api_event->time_stamp_sec, wp_tdm_api_event->time_stamp_usec);
293 
294  switch(wp_tdm_api_event->wp_api_event_type)
295  {
296  case WP_API_EVENT_DTMF:/* DTMF detected by Hardware */
297  DBG_MAIN("DTMF Event: Digit: %c (Port: %s, Type:%s)!\n",
298  wp_tdm_api_event->wp_api_event_dtmf_digit,
299  WAN_EC_DECODE_CHANNEL_PORT(wp_tdm_api_event->wp_api_event_dtmf_port), /* sout, rout, sin, rin */
300  WAN_EC_DECODE_TONE_TYPE(wp_tdm_api_event->wp_api_event_dtmf_type) /* present or stop */ );
301  break;
302 
303  case WP_API_EVENT_RXHOOK:
304  DBG_MAIN("RXHOOK Event: %s! (0x%X)\n",
305  WAN_EVENT_RXHOOK_DECODE(wp_tdm_api_event->wp_api_event_hook_state),
306  wp_tdm_api_event->wp_api_event_hook_state);
307  break;
308 
309  case WP_API_EVENT_RING_DETECT:
310  DBG_MAIN("RING Event: %s! (0x%X)\n",
311  WAN_EVENT_RING_DECODE(wp_tdm_api_event->wp_api_event_ring_state),
312  wp_tdm_api_event->wp_api_event_ring_state);
313  break;
314 
315  case WP_API_EVENT_RING_TRIP_DETECT:
316  DBG_MAIN("RING TRIP Event: %s! (0x%X)\n",
317  WAN_EVENT_RING_TRIP_DECODE(wp_tdm_api_event->wp_api_event_ring_state),
318  wp_tdm_api_event->wp_api_event_ring_state);
319  break;
320 
321  case WP_API_EVENT_RBS:
322  DBG_MAIN("RBS Event: New bits: 0x%X!\n", wp_tdm_api_event->wp_api_event_rbs_bits);
323  DBG_MAIN("RX RBS/CAS: ");
324  wp_print_rbs_cas_bits(wp_tdm_api_event->wp_api_event_rbs_bits);
325  break;
326 
327  case WP_API_EVENT_LINK_STATUS:
328  DBG_MAIN("Link Status Event: %s! (0x%X)\n",
329  WAN_EVENT_LINK_STATUS_DECODE(wp_tdm_api_event->wp_api_event_link_status),
330  wp_tdm_api_event->wp_api_event_link_status);
331  break;
332 
333  case WP_API_EVENT_ALARM:
334  DBG_MAIN("New Alarm State: 0x%X\n", wp_tdm_api_event->wp_api_event_alarm);
335  break;
336 
337  case WP_API_EVENT_POLARITY_REVERSE:
338  /* This event may have different meaning on different Telco lines.
339  * For example, it indicates "Network Initiated Clearing",
340  * on a British Telecom line. But on some lines it means
341  * "Start of Caller ID transmission". Please consult with your Telco
342  * for exact meaning of event. */
343  DBG_MAIN("Polarity Reversal Event: %s\n",
344  WP_API_EVENT_POLARITY_REVERSE_DECODE(wp_tdm_api_event->wp_api_event_polarity_reverse));
345  break;
346 
347  default:
348  ERR_MAIN("Unknown TDM API Event: %d\n", wp_tdm_api_event->wp_api_event_type);
349  break;
350  }
351 
352  LeaveCriticalSection(&TdmEventCriticalSection);
353  return;
354 }
355 
356 #if USE_WP_LOGGER
357 
364 static void got_logger_event(void *sang_if_ptr, wp_logger_event_t *logger_event)
365 {
366  char *timestamp_str = sangoma_ctime( &logger_event->time_stamp_sec );
367 
368  INFO_MAIN("Logger Event Type:\t%s (Logger:%d BitMap: 0x%08X)\n",
369  wp_decode_logger_event_type(logger_event->logger_type, logger_event->event_type),
370  logger_event->logger_type, logger_event->event_type);
371  /* Display Logger Event Timestamp as UNIX-style Date string. */
372  INFO_MAIN("Time and Date:\t\t%s\n",
373  (timestamp_str == NULL ? "Invalid Timestamp" : timestamp_str));
374  INFO_MAIN("Logger Event Data: %s\n\n", logger_event->data);
375 }
376 #endif
377 
386 {
387  FILE *pFile;
388  unsigned int tx_counter=0, bytes_read_from_file, total_bytes_read_from_file=0;
389  wp_api_hdr_t hdr;
390  unsigned char local_tx_data[SAMPLE_CPP_MAX_DATA_LEN];
391 
392  pFile = fopen( program_settings.szTxFileName, "rb" );
393  if( pFile == NULL){
394  ERR_MAIN( "Can't open file: [%s]\n", program_settings.szTxFileName );
395  return 1;
396  }
397 
398  do
399  {
400  //read tx data from the file. if 'bytes_read_from_file != txlength', end of file is reached
401  bytes_read_from_file = fread( local_tx_data, 1, program_settings.txlength /* MTU size */, pFile );
402  total_bytes_read_from_file += bytes_read_from_file;
403 
404  hdr.data_length = program_settings.txlength;//ALWAYS transmit MTU size over the BitStream/Voice interface
406 
407  if(SANG_STATUS_SUCCESS != sang_if->transmit(&hdr, local_tx_data)){
408  //error
409  break;
410  }
411 
412  tx_counter++;
413 
414  //DBG_MAIN("tx_counter: %u\r",tx_counter);
415 
416  }while(bytes_read_from_file == program_settings.txlength);
417 
418  INFO_MAIN("%s: Finished transmitting file \"%s\" (tx_counter: %u, total_bytes_read_from_file: %d)\n",
419  sang_if->device_name, program_settings.szTxFileName, tx_counter, total_bytes_read_from_file);
420 
421  fclose( pFile );
422  return 0;
423 }
424 
430 static int get_user_decimal_number()
431 {
432  int result = 1;
433  int retry_counter = 0;
434 
435  while(scanf("%d", &result) == 0){
436  fflush( stdin );
437  INFO_MAIN("\nError: Not a numerical input!!\n");
438  if(retry_counter++ > 10){
439  INFO_MAIN("giving up...\n");
440  result = 1;
441  break;
442  }
443  }//while()
444 
445  INFO_MAIN("User input: %d\n", result);
446  return result;
447 }
448 
454 static int get_user_hex_number()
455 {
456  int result = 1;
457  int retry_counter = 0;
458 
459  while(scanf("%x", &result) == 0){
460  fflush( stdin );
461  INFO_MAIN("\nError: Not a HEX input!!\n");
462  if(retry_counter++ > 10){
463  INFO_MAIN("giving up...\n");
464  result = 1;
465  break;
466  }
467  }//while()
468 
469  INFO_MAIN("User input: 0x%X\n", result);
470  return result;
471 }
472 
480 static int parse_command_line_args(int argc, char* argv[])
481 {
482  int i;
483  const char *USAGE_STR =
484 "\n"
485 "Usage: sample [-c] [-i] [options]\n"
486 "\n"
487 "\t-c number Wanpipe (Port/Span) number: 1,2,3...\n"
488 "\t-i number Interface number 1,2,3,....\n"
489 "options:\n"
490 "\t-silent Disable display of Rx data\n"
491 "\t-driver_config \tStop/Set Configuration/Start a Port....\n"
492 "\t-rx2tx All received data automatically transmitted on\n"
493 "\t the SAME interface\n"
494 "\t-txlength\tnumber\tLength of data frames to be transmitted when 't'\n"
495 "\t \t \tkey is pressed\n"
496 "\t-txcount\tnumber Number of test data frames to be transmitted when 't'\n"
497 "\t \t \tkey is pressed\n"
498 "\t-tx_file_name\tstring\tFile to be transmitted when 't' key is pressed\n"
499 #if USE_STELEPHONY_API
500 "\t-decode_fsk_cid\t\tDecode FSK Caller ID on an Analog line.\n"
501 "\t \t\tFor Voice data only.\n"
502 "\t-encode_fsk_cid\t\tEncode FSK Caller ID on an Analog line.\n"
503 "\t \t\tFor Voice data only.\n"
504 "\t-encode_sw_dtmf\t\tEncode SW DTMF on an line. For Voice data only.\n"
505 "\t-sw_dtmf Enable Sangoma Software DTMF decoder. For Voice data only.\n"
506 "\t-decode_q931 Enable Sangoma Q931 decoder. For HDLC (Dchannel) data only.\n"
507 "\t-alaw\t\t Use Alaw codec instead of default MuLaw codec for Voice data.\n"
508 "\t-rm_txgain\t Set txgain for FXS/FXO modules.\n"
509 "\t \t\tFXO range from -150 to 120, FXS 35 or -35\n"
510 "\t-rm_rxgain\t Set txgain for FXS/FXO modules.\n"
511 "\t \t\tFXO range from -150 to 120, FXS 35 or -35\n"
512 #endif
513 #if 0
514 "\t-use_ctrl_dev \tUse the global 'wptdm_ctrl' device to Get events from\n"
515 "\t \tall API devices.\n"
516 #endif
517 "\t-use_logger_dev \tUse the global Logger device to Get Log Messages\n"
518 "\t \tfrom API driver.\n"
519 #ifdef WP_API_FEATURE_LIBSNG_HWEC
520 "\t-use_hwec \tInitialize/Configure/Use the Hardware Echo Canceller\n"
521 "\t-hwec_chan \tA 1-based channel number to be used by per-channel (vs. global)\n"
522 "\t \tHWEC functions. Valid values: 1-31\n"
523 #endif
524 #if USE_BUFFER_MULTIPLIER
525 "\t-buff_mult\tnumber\tBuffer Multiplier coefficient\n"
526 #endif
527 "\t-real_time \tRun the Program at real-time priority. This maybe\n"
528 "\t \t\timportant when Audio stream is used for timing.\n"
529 "\n"
530 "Example: sample -c 1 -i 1\n";
531 
532  memset(&program_settings, 0, sizeof(wp_program_settings_t));
533  program_settings.wanpipe_number = 1;
534  program_settings.interface_number = 1;
535  program_settings.txlength = 80;
536  program_settings.txcount = 1;
537  program_settings.rxgain = 0xFFFF; //FXO/FXS rx gain unchanged
538  program_settings.txgain = 0xFFFF; //FXO/FXS tx gain unchanged
539  program_settings.hwec_channel = 1;
540 #if USE_BUFFER_MULTIPLIER
541  program_settings.buffer_multiplier = MIN_BUFFER_MULTIPLIER_FACTOR; //1
542 #endif
543 
544  for(i = 1; i < argc;){
545 
546  if(_stricmp(argv[i], "-silent") == 0){
547  INFO_MAIN("disabling Rx data display...\n");
548  program_settings.silent = 1;
549  }else if(_stricmp(argv[i], "help") == 0 || _stricmp(argv[i], "?") == 0 || _stricmp(argv[i], "/?") == 0){
550  INFO_MAIN(USAGE_STR);
551  return 1;
552  }else if(_stricmp(argv[i], "-c") == 0){
553  if (i+1 > argc-1){
554  INFO_MAIN("No Wanpipe number was provided!\n");
555  return 1;
556  }
557  program_settings.wanpipe_number = (uint16_t)atoi(argv[i+1]);
558  INFO_MAIN("Using wanpipe number %d\n", program_settings.wanpipe_number);
559  i++;
560  }else if(_stricmp(argv[i], "-i") == 0){
561  if (i+1 > argc-1){
562  INFO_MAIN("No Interface number was provided!\n");
563  return 1;
564  }
565  program_settings.interface_number = (uint16_t)atoi(argv[i+1]);
566  INFO_MAIN("Using interface number %d\n", program_settings.interface_number);
567  if(program_settings.interface_number < 1){
568  ERR_MAIN("Invalid interface number %d!!\n", program_settings.interface_number);
569  return 1;
570  }
571  i++;
572  }else if(strcmp(argv[i], "-rx2tx") == 0){
573  INFO_MAIN("enabling Rx to Tx loopback...\n");
574  program_settings.Rx_to_Tx_loopback = 1;
575  }else if(strcmp(argv[i], "-driver_config") == 0){
576  INFO_MAIN("enabling driver config start/stop\n");
577  program_settings.driver_config = 1;
578 
579  }else if(_stricmp(argv[i], "-txlength") == 0){
580  if (i+1 > argc-1){
581  INFO_MAIN("No txlength provided!\n");
582  return 1;
583  }
584  program_settings.txlength = (uint16_t)atoi(argv[i+1]);
585  INFO_MAIN("Setting txlength to %d bytes.\n", program_settings.txlength);
586  i++;
587  }else if(_stricmp(argv[i], "-txcount") == 0){
588  if (i+1 > argc-1){
589  INFO_MAIN("No txcount provided!\n");
590  return 1;
591  }
592  program_settings.txcount = atoi(argv[i+1]);
593  i++;
594  INFO_MAIN("Setting txcount to %d.\n", program_settings.txcount);
595 #if USE_STELEPHONY_API
596  }else if(_stricmp(argv[i], "-decode_fsk_cid") == 0){
597  INFO_MAIN("enabling FSK Caller ID decoder...\n");
598  program_settings.decode_fsk_cid = 1;
599  callback_functions.FSKCallerIDEvent = FSKCallerIDEvent;
600  }else if(_stricmp(argv[i], "-sw_dtmf") == 0){
601  INFO_MAIN("enabling Software DTMF decoder...\n");
602  program_settings.sw_dtmf = 1;
603  callback_functions.DTMFEvent = DTMFEvent;
604  }else if(_stricmp(argv[i], "-decode_q931") == 0){
605  INFO_MAIN("enabling Q931 decoder...\n");
606  program_settings.decode_q931 = 1;
607  callback_functions.Q931Event = Q931Event;
608  }else if(_stricmp(argv[i], "-encode_fsk_cid") == 0){
609  INFO_MAIN("enabling FSK Caller ID encoder...\n");
610  program_settings.encode_fsk_cid = 1;
611  callback_functions.FSKCallerIDTransmit = FSKCallerIDTransmit;
612  }else if(_stricmp(argv[i], "-encode_sw_dtmf") == 0){
613  INFO_MAIN("enabling Software DTMF encoder...\n");
614  program_settings.encode_sw_dtmf = 1;
615  callback_functions.SwDtmfTransmit = SwDtmfTransmit;
616  }else if(_stricmp(argv[i], "-alaw") == 0){
617  INFO_MAIN("enabling ALaw codec...\n");
618  program_settings.voice_codec_alaw = 1;
619 #endif//USE_STELEPHONY_API
620  }else if(_stricmp(argv[i], "-tx_file_name") == 0){
621  if (i+1 > argc-1){
622  INFO_MAIN("No TxFileName provided!\n");
623  return 1;
624  }
625  strcpy(program_settings.szTxFileName, argv[i+1]);
626  i++;
627  INFO_MAIN("Setting szTxFileName to '%s'.\n", program_settings.szTxFileName);
628  }else if(_stricmp(argv[i], "-use_ctrl_dev") == 0){
629  INFO_MAIN("Using ctrl_dev...\n");
630  program_settings.use_ctrl_dev = 1;
631  }else if(_stricmp(argv[i], "-use_logger_dev") == 0){
632  INFO_MAIN("Using logger_dev...\n");
633  program_settings.use_logger_dev = 1;
634  }else if(_stricmp(argv[i], "-rm_txgain") == 0){
635  if (i+1 > argc-1){
636  INFO_MAIN("No Tx gain provided!\n");
637  return 1;
638  }
639  program_settings.txgain = atoi(argv[i+1]);
640  i++;
641  INFO_MAIN("Setting Tx gain to %d.\n", program_settings.txgain);
642  }else if(_stricmp(argv[i], "-rm_rxgain") == 0){
643  if (i+1 > argc-1){
644  INFO_MAIN("No Rx gain provided!\n");
645  return 1;
646  }
647  program_settings.rxgain = atoi(argv[i+1]);
648  i++;
649  INFO_MAIN("Setting Rx gain to %d.\n", program_settings.txgain);
650  }else if(_stricmp(argv[i], "-use_hwec") == 0){
651  INFO_MAIN("Using hardware echo canceller...\n");
652  program_settings.use_hardware_echo_canceller = 1;
653  }else if(_stricmp(argv[i], "-hwec_chan") == 0){
654  if (i+1 > argc-1){
655  INFO_MAIN("No hwec_chan provided!\n");
656  return 1;
657  }
658  program_settings.hwec_channel = atoi(argv[i+1]);
659  i++;
660  INFO_MAIN("Setting hwec_chan to %d.\n", program_settings.hwec_channel);
661  }else if(_stricmp(argv[i], "-real_time") == 0){
662  INFO_MAIN("Will be running at real-time priority...\n");
663  program_settings.real_time = 1;
664 #if USE_BUFFER_MULTIPLIER
665  }else if(_stricmp(argv[i], "-buff_mult") == 0){
666  if (i+1 > argc-1){
667  INFO_MAIN("No buff_mult provided!\n");
668  return 1;
669  }
670  program_settings.buffer_multiplier = atoi(argv[i+1]);
671  i++;
672  INFO_MAIN("Setting buff_mult to %d.\n", program_settings.buffer_multiplier);
673 #endif
674  }else{
675  INFO_MAIN("Error: Invalid Argument %s\n",argv[i]);
676  return 1;
677  }
678  i++;
679  }
680  return 0;
681 }
682 
683 
684 int my_getch()
685 {
686  string str_input = "";
687 
688  std::getline(cin, str_input);
689 
690  return str_input.c_str()[0];
691 }
692 
693 
709 int __cdecl main(int argc, char* argv[])
710 {
711  int rc, user_selection,err;
712  sangoma_interface *sang_if = NULL;
713  wp_api_hdr_t hdr;
714  unsigned char local_tx_data[SAMPLE_CPP_MAX_DATA_LEN];
715  UCHAR tx_test_byte = 0;
716 
718  memset(&callback_functions, 0x00, sizeof(callback_functions));
719  callback_functions.got_rx_data = got_rx_data;
720  callback_functions.got_tdm_api_event = got_tdm_api_event;
721 #if USE_WP_LOGGER
722  callback_functions.got_logger_event = got_logger_event;
723 #endif
724  if(parse_command_line_args(argc, argv)){
726  return 1;
727  }
728 
730  //An OPTIONAL step of setting the port configuration to different values from
731  //what is set in "Device Manager"-->"Sangoma Hardware Abstraction Driver".
732 
733  //set port configration and exit
734  if (program_settings.driver_config) {
735  err=set_port_configuration();
736  if (err) {
737  return err;
738  }
739  }
740 
742  //initialize critical section objects
743  InitializeCriticalSection(&PrintCriticalSection);
744  InitializeCriticalSection(&TdmEventCriticalSection);
745 
746  if (program_settings.real_time) {
747  sng_set_process_priority_to_real_time();
748  }
749 
751  //User may provide Wanpipe Number and Interface Number as a command line arguments:
752  INFO_MAIN("Using wanpipe_number: %d, interface_number: %d\n", program_settings.wanpipe_number, program_settings.interface_number);
753 
754  sang_if = init(program_settings.wanpipe_number, program_settings.interface_number);
755 
756  if(sang_if == NULL){
757  return 1;
758  }
759 
760  rc = start(sang_if);
761  if(rc){
762  cleanup(sang_if);
763  return rc;
764  }
765 
766  if(program_settings.txgain != 0xFFFF) {
767  INFO_MAIN("Applying txgain...\n");
768  if (sang_if->tdm_control_rm_txgain(program_settings.txgain)){
769  INFO_MAIN("Failed to apply txgain!\n");
770  }
771  }
772 
773  /* FXS cannot detect if phone is connected or not when the card is started
774  therefore tranmit following two events for Set Polarity to work */
775  if(sang_if->get_adapter_type() == WAN_MEDIA_FXOFXS && sang_if->get_sub_media() == MOD_TYPE_FXS) {
776  INFO_MAIN("Setting Proper hookstates on FXS\n");
777  sang_if->tdm_txsig_offhook();
778  sang_if->tdm_txsig_onhook();
779  }
780 
781  if(program_settings.rxgain != 0xFFFF) {
782  INFO_MAIN("Applying rxgain...\n");
783  if (sang_if->tdm_control_rm_rxgain(program_settings.rxgain)){
784  INFO_MAIN("Failed to apply rxgain!\n");
785  }
786  }
787  do{
788  EnterCriticalSection(&PrintCriticalSection);
789 
790  INFO_MAIN("Press 'q' to quit the program.\n");
791  INFO_MAIN("Press 's' to get Operational Statistics.\n");
792  INFO_MAIN("Press 'f' to reset (flush) Operational Statistics.\n");
793 
794  if(program_settings.use_logger_dev != 1){
795  /* these options valid for non-logger api devices */
796  INFO_MAIN("Press 't' to transmit data.\n");
797  INFO_MAIN("Press 'v' to get API driver version.\n");
798 
799  if(sang_if->get_adapter_type() == WAN_MEDIA_T1 || sang_if->get_adapter_type() == WAN_MEDIA_E1){
800  INFO_MAIN("Press 'a' to get T1/E1 alarms.\n");
801  //RBS (CAS) commands
802  INFO_MAIN("Press 'g' to get RBS bits.\n");
803  INFO_MAIN("Press 'r' to set RBS bits.\n");
804  INFO_MAIN("Press '1' to read FE register. Warning: used by Sangoma Techsupport only!\n");
805  INFO_MAIN("Press '2' to write FE register. Warning: used by Sangoma Techsupport only!\n");
806  }
807  INFO_MAIN("Press 'i' to set Tx idle data buffer (BitStream only).\n");
808  switch(sang_if->get_adapter_type())
809  {
810  case WAN_MEDIA_T1:
811  //those commands valid only for T1
812  INFO_MAIN("Press 'l' to send 'activate remote loop back' signal.\n");
813  INFO_MAIN("Press 'd' to send 'deactivate remote loop back' signal.\n");
814  break;
815  case WAN_MEDIA_FXOFXS:
816  switch(sang_if->get_sub_media())
817  {
818  case MOD_TYPE_FXS:
819  INFO_MAIN("Press 'e' to listen to test tones on a phone connected to the A200-FXS\n");
820  INFO_MAIN("Press 'c' to ring/stop ring phone connected to the A200-FXS\n");
821  INFO_MAIN("Press 'n' to enable/disable reception of ON/OFF Hook events on A200-FXS\n");
822  INFO_MAIN("Press 'm' to enable DTMF events (on SLIC chip) on A200-FXS\n");
823  INFO_MAIN("Press 'j 'to enable/disable reception of Ring Trip events on A200-FXS\n");
824  INFO_MAIN("Press 'k' to transmit kewl - drop line voltage on the line connected to the A200-FXS\n");
825  INFO_MAIN("Press 'h' to set polarity on the line connected to the A200-fXS\n");
826  INFO_MAIN("Press 'u' to transmit onhooktransfer on the line connected to the A200-FXS\n");
827  break;
828 
829  case MOD_TYPE_FXO:
830  INFO_MAIN("Press 'u' to enable/disable reception of Ring Detect events on A200-FXO\n");
831  INFO_MAIN("Press 'h' to transmit ON/OFF hook signals on A200-FXO\n");
832  INFO_MAIN("Press 'a' to get Line Status (Connected/Disconnected)\n");
833  break;
834  }
835  break;
836  case WAN_MEDIA_BRI:
837  INFO_MAIN("Press 'k' to Activate/Deactivate ISDN BRI line\n");
838  INFO_MAIN("Press 'l' to enable bri bchan loopback\n");
839  INFO_MAIN("Press 'd' to disable bri bchan loopback\n");
840  break;
841  }
842  INFO_MAIN("Press 'o' to control DTMF events on DSP (Octasic)\n");
843  if (program_settings.encode_sw_dtmf) {
844  INFO_MAIN("Press 'x' to send software DTMF\n");
845  }
846  if (program_settings.encode_fsk_cid) {
847  INFO_MAIN("Press 'z' to send software FSK Caller ID\n");
848  }
849  }//if(program_settings.use_logger_dev != 1)
850 
851  LeaveCriticalSection(&PrintCriticalSection);
852  user_selection = tolower(my_getch());
853  switch(user_selection)
854  {
855  case 'q':
856  break;
857  case 't':
858  for(u_int32_t cnt = 0; cnt < program_settings.txcount; cnt++){
859  if(program_settings.szTxFileName[0]){
860  tx_file(sang_if);
861  }else{
862  hdr.data_length = program_settings.txlength;
864  //set the actual data for transmission
865  memset(local_tx_data, tx_test_byte, program_settings.txlength);
866  sang_if->transmit(&hdr, local_tx_data);
867  tx_test_byte++;
868  }
869  }
870  break;
871  case 's':
872  if(program_settings.use_logger_dev == 1){
873  wp_logger_stats_t stats;
874  /* Warning: for demonstration purposes only, it is assumed,
875  * that 'sang_if' is 'sangoma_api_logger_dev'. */
876  ((sangoma_api_logger_dev*)sang_if)->get_logger_dev_operational_stats(&stats);
877  }else{
878  wanpipe_chan_stats_t stats;
879  sang_if->get_operational_stats(&stats);
880  }
881  break;
882  case 'f':
883  sang_if->flush_operational_stats();
884  break;
885  case 'v':
886  {
887  DRIVER_VERSION version;
888  //read API driver version
889  sang_if->get_api_driver_version(&version);
890  INFO_MAIN("\nAPI version\t: %d,%d,%d,%d\n",
891  version.major, version.minor, version.minor1, version.minor2);
892 
893  u_int8_t customer_id = 0;
894  sang_if->get_card_customer_id(&customer_id);
895  INFO_MAIN("\ncustomer_id\t: 0x%02X\n", customer_id);
896  }
897  break;
898  case 'a':
899  unsigned char cFeStatus;
900 
901  switch(sang_if->get_adapter_type())
902  {
903  case WAN_MEDIA_T1:
904  case WAN_MEDIA_E1:
905  //read T1/E1/56k alarms
906  sang_if->get_te1_56k_stat();
907  break;
908 
909  case WAN_MEDIA_FXOFXS:
910  switch(sang_if->get_sub_media())
911  {
912  case MOD_TYPE_FXO:
913  cFeStatus = 0;
914  sang_if->tdm_get_front_end_status(&cFeStatus);
915  INFO_MAIN("cFeStatus: %s (%d)\n", FE_STATUS_DECODE(cFeStatus), cFeStatus);
916  break;
917  }
918  }
919  break;
920  case 'l':
921  switch(sang_if->get_adapter_type())
922  {
923  case WAN_MEDIA_T1:
924  case WAN_MEDIA_E1:
925  //Activate Line/Remote Loopback mode:
926  sang_if->set_lb_modes(WAN_TE1_LINELB_MODE, WAN_TE1_LB_ENABLE);
927  //Activate Diagnostic Digital Loopback mode:
928  //sang_if->set_lb_modes(WAN_TE1_DDLB_MODE, WAN_TE1_LB_ENABLE);
929  //sang_if->set_lb_modes(WAN_TE1_PAYLB_MODE, WAN_TE1_LB_ENABLE);
930  break;
931  case WAN_MEDIA_BRI:
932  sang_if->tdm_enable_bri_bchan_loopback(WAN_BRI_BCHAN1);
933  break;
934  }
935  break;
936  case 'd':
937  switch(sang_if->get_adapter_type())
938  {
939  case WAN_MEDIA_T1:
940  case WAN_MEDIA_E1:
941  //Deactivate Line/Remote Loopback mode:
942  sang_if->set_lb_modes(WAN_TE1_LINELB_MODE, WAN_TE1_LB_DISABLE);
943  //Deactivate Diagnostic Digital Loopback mode:
944  //sang_if->set_lb_modes(WAN_TE1_DDLB_MODE, WAN_TE1_LB_DISABLE);
945  //sang_if->set_lb_modes(WAN_TE1_PAYLB_MODE, WAN_TE1_LB_DISABLE);
946  break;
947  case WAN_MEDIA_BRI:
948  sang_if->tdm_disable_bri_bchan_loopback(WAN_BRI_BCHAN1);
949  break;
950  }
951  break;
952  case 'g'://read RBS bits
953  switch(sang_if->get_adapter_type())
954  {
955  case WAN_MEDIA_T1:
956  case WAN_MEDIA_E1:
957  {
958  rbs_management_t rbs_management_struct = {0,0};
959 
960  sang_if->enable_rbs_monitoring();
961 
962  INFO_MAIN("Type Channel number and press <Enter>:\n");
963  rbs_management_struct.channel = get_user_decimal_number();//channels (Time Slots). Valid values: 1 to 24.
964 
965  if(WAN_MEDIA_T1 == sang_if->get_adapter_type()){
966  if(rbs_management_struct.channel < 1 || rbs_management_struct.channel > 24){
967  INFO_MAIN("Invalid T1 RBS Channel number!\n");
968  break;
969  }
970  }
971 
972  if(WAN_MEDIA_E1 == sang_if->get_adapter_type()){
973  if(rbs_management_struct.channel < 1 || rbs_management_struct.channel > 31){
974  INFO_MAIN("Invalid E1 CAS Channel number!\n");
975  break;
976  }
977  }
978 
979  sang_if->get_rbs(&rbs_management_struct);
980  }
981  break;
982  default:
983  INFO_MAIN("Command invalid for card type\n");
984  break;
985  }//switch()
986  break;
987  case 'r'://set RBS bits
988  switch(sang_if->get_adapter_type())
989  {
990  case WAN_MEDIA_T1:
991  case WAN_MEDIA_E1:
992  {
993  static rbs_management_t rbs_management_struct = {0,0};
994  int chan_no;
995 
996  sang_if->enable_rbs_monitoring();
997 
998  INFO_MAIN("Type Channel number and press <Enter>:\n");
999  rbs_management_struct.channel = chan_no = get_user_decimal_number();//channels (Time Slots). Valid values: T1: 1 to 24; E1: 1-15 and 17-31.
1000 
1001  if(WAN_MEDIA_T1 == sang_if->get_adapter_type()){
1002  if(rbs_management_struct.channel < 1 || rbs_management_struct.channel > 24){
1003  INFO_MAIN("Invalid T1 RBS Channel number!\n");
1004  break;
1005  }
1006  }
1007 
1008  if(WAN_MEDIA_E1 == sang_if->get_adapter_type()){
1009  if(rbs_management_struct.channel < 1 || rbs_management_struct.channel > 31){
1010  INFO_MAIN("Invalid E1 CAS Channel number!\n");
1011  break;
1012  }
1013  }
1014 
1015  /* bitmap - set as needed: WAN_RBS_SIG_A | WAN_RBS_SIG_B | WAN_RBS_SIG_C | WAN_RBS_SIG_D;
1016 
1017  In this example make bits A and B to change each time,
1018  so it's easy to see the change on the receiving side.
1019  */
1020  if(rbs_management_struct.ABCD_bits == WAN_RBS_SIG_A){
1021  rbs_management_struct.ABCD_bits = WAN_RBS_SIG_B;
1022  }else{
1023  rbs_management_struct.ABCD_bits = WAN_RBS_SIG_A;
1024  }
1025  sang_if->set_rbs(&rbs_management_struct);
1026 
1027 #if 0
1028 #define RBS_CAS_TX_AND_WAIT(chan, abcd) \
1029 { \
1030  rbs_management_struct.channel = chan; \
1031  rbs_management_struct.ABCD_bits = abcd; \
1032  INFO_MAIN("Press any key to transmit bits:"); \
1033  wp_print_rbs_cas_bits(abcd); \
1034  my_getch(); \
1035  sang_if->set_rbs(&rbs_management_struct); \
1036 }
1037 
1038  //for ESF lines test all all combinations of 4 bits
1039  RBS_CAS_TX_AND_WAIT(chan_no, 0x00);
1040 
1041  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_A);
1042 
1043  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_B);
1044 
1045  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_A | WAN_RBS_SIG_B);
1046 
1047  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_C);
1048 
1049  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_A | WAN_RBS_SIG_C);
1050 
1051  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_B | WAN_RBS_SIG_C);
1052 
1053  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_A | WAN_RBS_SIG_B | WAN_RBS_SIG_C);
1054 
1055  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_D);
1056 
1057  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_A | WAN_RBS_SIG_D);
1058 
1059  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_B | WAN_RBS_SIG_D);
1060 
1061  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_A | WAN_RBS_SIG_B | WAN_RBS_SIG_D);
1062 
1063  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_C | WAN_RBS_SIG_D);
1064 
1065  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_A | WAN_RBS_SIG_C | WAN_RBS_SIG_D);
1066 
1067  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_B | WAN_RBS_SIG_C | WAN_RBS_SIG_D);
1068 
1069  RBS_CAS_TX_AND_WAIT(chan_no, WAN_RBS_SIG_A | WAN_RBS_SIG_B | WAN_RBS_SIG_C | WAN_RBS_SIG_D);
1070 #endif
1071  }
1072  break;
1073  default:
1074  INFO_MAIN("Command invalid for card type\n");
1075  break;
1076  }//switch()
1077  break;
1078  case 'i':
1079  {
1080  INFO_MAIN("Type Idle Flag (HEX, for example: FE) and press <Enter>:\n");
1081  unsigned char new_idle_flag = (unsigned char)get_user_hex_number();
1082  sang_if->set_tx_idle_flag(new_idle_flag);
1083  }
1084  break;
1085  case 'c':
1086 user_retry_ring_e_d:
1087  INFO_MAIN("Press 'e' to START ring, 'd' to STOP ring, 't' to Toggle\n");
1088  INFO_MAIN("\n");
1089  user_selection = tolower(my_getch());
1090  switch(user_selection)
1091  {
1092  case 'e':
1093  INFO_MAIN("Starting Ring ...%c\n",user_selection);
1094  sang_if->start_ringing_phone();//start
1095  break;
1096  case 'd':
1097  INFO_MAIN("Stopping Ring ... %c\n",user_selection);
1098  sang_if->stop_ringing_phone();//stop
1099  break;
1100  case 't':
1101  {
1102  int x;
1103  for (x=0;x<500;x++) {
1104  sang_if->start_ringing_phone();
1105  sang_if->start_ringing_phone();
1106  //sangoma_msleep(500);
1107  sang_if->stop_ringing_phone();//stop
1108  sang_if->stop_ringing_phone();//stop
1109  //sangoma_msleep(500);
1110  sang_if->start_busy_tone();
1111  sangoma_msleep(50);
1112  sang_if->stop_all_tones();
1113  sangoma_msleep(50);
1114  }
1115  }
1116  break;
1117  default:
1118  goto user_retry_ring_e_d;
1119  break;
1120  }
1121  break;
1122  case 'e':
1123  INFO_MAIN("Press 'e' to START a Tone, 'd' to STOP a Tone.\n");
1124  INFO_MAIN("\n");
1125 
1126  switch(tolower(my_getch()))
1127  {
1128  case 'e':
1129  INFO_MAIN("Press 'r' for Ring Tone, 'd' for Dial Tone, 'b' for Busy Tone, 'c' for Congestion Tone.\n");
1130  INFO_MAIN("\n");
1131  switch(tolower(my_getch()))
1132  {
1133  case 'r':
1134  sang_if->start_ring_tone();
1135  break;
1136  case 'd':
1137  sang_if->start_dial_tone();
1138  break;
1139  case 'b':
1140  sang_if->start_busy_tone();
1141  break;
1142  case 'c':
1143  default:
1144  sang_if->start_congestion_tone();
1145  break;
1146  }
1147  break;
1148 
1149  case 'd':
1150  default:
1151  sang_if->stop_all_tones();//stop all tones
1152  }
1153  break;
1154  case 'n':
1155  INFO_MAIN("Press 'e' to ENABLE Rx Hook Events, 'd' to DISABLE Rx Hook Events.\n");
1156  INFO_MAIN("\n");
1157  switch(tolower(my_getch()))
1158  {
1159  case 'e':
1160  sang_if->tdm_enable_rxhook_events();
1161  break;
1162  case 'd':
1163  default:
1164  sang_if->tdm_disable_rxhook_events();
1165  }
1166  break;
1167  case 'm':
1168  //Enable/Disable DTMF events on SLIC chip.
1169  //On Analog (A200) card only.
1170  INFO_MAIN("Press 'e' to ENABLE Remora DTMF Events, 'd' to DISABLE Remora DTMF Events.\n");
1171  INFO_MAIN("\n");
1172  switch(tolower(my_getch()))
1173  {
1174  case 'e':
1175  sang_if->tdm_enable_rm_dtmf_events();
1176  break;
1177  case 'd':
1178  default:
1179  sang_if->tdm_disable_rm_dtmf_events();
1180  }
1181  break;
1182  case 'o':
1183  {
1184  //Enable DTMF events on Octasic chip.
1185  //For both Analog (A200) and T1/E1 (A104D) cards, but only if the chip is present.
1186  INFO_MAIN("Press 'e' to ENABLE Octasic DTMF Events, 'd' to DISABLE Octasic DTMF Events.\n");
1187  uint8_t channel;
1188 
1189  INFO_MAIN("\n");
1190  switch(tolower(my_getch()))
1191  {
1192  case 'e':
1193  INFO_MAIN("Type Channel number and press <Enter>:\n");
1194  channel = (uint8_t)get_user_decimal_number();//channels (Time Slots). Valid values: 1 to 31.
1195 
1196  sang_if->tdm_enable_dtmf_events(channel);
1197  break;
1198  case 'd':
1199  default:
1200  INFO_MAIN("Type Channel number and press <Enter>:\n");
1201  channel = (uint8_t)get_user_decimal_number();//channels (Time Slots). Valid values: 1 to 31.
1202 
1203  sang_if->tdm_disable_dtmf_events(channel);
1204  }
1205  }
1206  break;
1207  case 'u':
1208  //Enable/Disable Ring Detect events on FXO.
1209  if(sang_if->get_sub_media()==MOD_TYPE_FXO){
1210  INFO_MAIN("Press 'e' to ENABLE Rx Ring Detect Events, 'd' to DISABLE Rx Ring Detect Events.\n");
1211  INFO_MAIN("\n");
1212  switch(tolower(my_getch()))
1213  {
1214  case 'e':
1215  sang_if->tdm_enable_ring_detect_events();
1216  break;
1217  case 'd':
1218  default:
1219  sang_if->tdm_disable_ring_detect_events();
1220  }
1221  }else if(sang_if->get_sub_media()==MOD_TYPE_FXS){
1222  sang_if->tdm_txsig_onhooktransfer();
1223  }
1224  break;
1225  case 'j':
1226  //Enable/Disable Ring Trip events on FXS.
1227  INFO_MAIN("Press 'e' to ENABLE Rx Ring Trip Events, 'd' to DISABLE Rx Ring Trip Events.\n");
1228  INFO_MAIN("\n");
1229  switch(tolower(my_getch()))
1230  {
1231  case 'e':
1232  sang_if->tdm_enable_ring_trip_detect_events();
1233  break;
1234  case 'd':
1235  default:
1236  sang_if->tdm_disable_ring_trip_detect_events();
1237  }
1238  break;
1239  case 'h':
1240  if(sang_if->get_sub_media()==MOD_TYPE_FXO) {
1241  INFO_MAIN("Press 'e' to transmit OFF hook signal, 'd' to transmit ON hook signal.\n");
1242  INFO_MAIN("\n");
1243  switch(tolower(my_getch()))
1244  {
1245  case 'e':
1246  sang_if->fxo_go_off_hook();
1247  break;
1248  case 'd':
1249  default:
1250  sang_if->fxo_go_on_hook();
1251  }
1252  }else if(sang_if->get_sub_media() == MOD_TYPE_FXS) {
1253  INFO_MAIN("Press 'f' for forward, 'r' to for reverse.\n");
1254  INFO_MAIN("\n");
1255  switch(tolower(my_getch()))
1256  {
1257  case 'f':
1258  sang_if->tdm_set_rm_polarity(0);
1259  break;
1260  case 'r':
1261  sang_if->tdm_set_rm_polarity(1);
1262  break;
1263  default:
1264  //toggle polarity
1265  int polarity_wait, two_second_ring_repetion_counter;
1266 
1267  INFO_MAIN("Type Polarity Reverse/Forward delay and press <Enter>:\n");
1268  polarity_wait = get_user_decimal_number();
1269  if (!polarity_wait) {
1270  ERR_MAIN("Invalid User-specified Polarity Reverse/Forward delay: %d!\n", polarity_wait);
1271  polarity_wait = 400;
1272  }
1273  /* polarity_wait of 30 ms will ring Analog phone or FXO
1274  * polarity_wait of 400 ms will cause Polarity reversal event on FXO */
1275  INFO_MAIN("User specified Polarity Reverse/Forward delay: %d. Press <Enter> to continue.\n", polarity_wait);
1276  my_getch();
1277 
1278  /* calculate number of iterations for a 2-second test */
1279  two_second_ring_repetion_counter = 2000 / (polarity_wait * 2);
1280  INFO_MAIN("two_second_ring_repetion_counter: %d. Press <Enter> to continue.\n", two_second_ring_repetion_counter);
1281  my_getch();
1282 
1283  for (int ii = 0; ii < two_second_ring_repetion_counter; ii++) {
1284  INFO_MAIN("Reversing polarity %d...\n", ii);
1285  sang_if->tdm_set_rm_polarity(1);
1286  sangoma_msleep(polarity_wait);
1287  INFO_MAIN("Forwarding polarity %d...\n", ii);
1288  sang_if->tdm_set_rm_polarity(0);
1289  sangoma_msleep(polarity_wait);
1290  }
1291 
1292  //sleep 4 seconds between the rings
1293  INFO_MAIN("4 seconds between the rings...\n");
1294  sangoma_msleep(4000);
1295 
1296  for (int ii = 0; ii < two_second_ring_repetion_counter; ii++) {
1297  INFO_MAIN("Reversing polarity %d...\n", ii);
1298  sang_if->tdm_set_rm_polarity(1);
1299  sangoma_msleep(polarity_wait);
1300  INFO_MAIN("Forwarding polarity %d...\n", ii);
1301  sang_if->tdm_set_rm_polarity(0);
1302  sangoma_msleep(polarity_wait);
1303  }//for()
1304  }//switch()
1305  }
1306  break;
1307  case 'k':
1308  if( sang_if->get_adapter_type() == WAN_MEDIA_BRI ) {
1309  INFO_MAIN("Press 'e' to Activate, 'd' to De-Activate line.\n");
1310  INFO_MAIN("\n");
1311  switch(tolower(my_getch()))
1312  {
1313  case 'e':
1314  sang_if->tdm_front_end_activate();
1315  break;
1316  case 'd':
1317  default:
1318  sang_if->tdm_front_end_deactivate();
1319  }
1320  }else if(sang_if->get_adapter_type()== WAN_MEDIA_FXOFXS) {
1321  if(sang_if->get_sub_media()==MOD_TYPE_FXS) {
1322  printf("calling tdm_txsig_kewl()...\n");
1323  sang_if->tdm_txsig_kewl();
1324  sangoma_msleep(5000);
1325  //to restore line current after txsig kewl
1326  printf("restoring line current after txsig kewl...\n");
1327  sang_if->tdm_txsig_offhook();
1328  }
1329  }
1330  break;
1331  case 'p':
1332  {
1333  int user_period;//Milliseconds interval between receive of Voice Data
1334  INFO_MAIN("Type User Period and press <Enter>. Valid values are: 10, 20, 40.\n");
1335  user_period = get_user_decimal_number();
1336  switch(user_period)
1337  {
1338  case 10:
1339  case 20:
1340  case 40:
1341  sang_if->tdm_set_user_period(user_period);
1342  break;
1343  default:
1344  INFO_MAIN("Invalid User Period value! Valid values are: 10, 20, 40.\n");
1345  break;
1346  }
1347  }
1348  break;
1349 #if USE_STELEPHONY_API
1350  case 'x':
1351  {
1352  INFO_MAIN("Press a key. Valid values are 0-9, A-C\n");
1353  int user_char = my_getch();
1354  switch(tolower(user_char)) {
1355  case '1': case '2': case '3':
1356  case '4': case '5': case '6':
1357  case '7': case '8': case '9':
1358  case '0': case 'a': case 'b':
1359  case 'c':
1360  INFO_MAIN("Sending DTMF (%c).\n", user_char);
1361  sang_if->sendSwDTMF((char)user_char);
1362  break;
1363  default:
1364  INFO_MAIN("Invalid DTMF Char! Valid values are: 0-9, A-C\n");
1365  break;
1366  }
1367  }
1368  break;
1369  case 'z':
1370  {
1371  if(WAN_MEDIA_FXOFXS == sang_if->get_adapter_type() && MOD_TYPE_FXS == sang_if->get_sub_media() ){
1372  //Ring the line
1373  sang_if->start_ringing_phone();
1374  sangoma_msleep(2000);
1375  //txsig offhook
1376  sang_if->fxs_txsig_offhook();
1377  INFO_MAIN("Sending CallerID.\n");
1378  sang_if->sendCallerID("Sangoma Rocks", "9054741990");
1379  }else{
1380  INFO_MAIN("Sending CallerID.\n");
1381  sang_if->sendCallerID("Sangoma Rocks", "9054741990");
1382  }
1383  }
1384  break;
1385 #endif
1386  case '1':/* read FE register */
1387  {
1388  int value;
1389  sdla_fe_debug_t fe_debug;
1390 
1391  fe_debug.type = WAN_FE_DEBUG_REG;
1392 
1393  printf("Type Register number (hex) i.g. F8 and press Enter:");
1394  value = get_user_hex_number();
1395 
1396  fe_debug.fe_debug_reg.reg = value;
1397  fe_debug.fe_debug_reg.read = 1;
1398 
1399  sang_if->set_fe_debug_mode(&fe_debug);
1400  }
1401  break;
1402 
1403  case '2':/* write FE register */
1404  {
1405  int value;
1406  sdla_fe_debug_t fe_debug;
1407  fe_debug.type = WAN_FE_DEBUG_REG;
1408 
1409  printf("WRITE: Type Register number (hex) i.g. F8 and press Enter:");
1410  value = get_user_hex_number();
1411 
1412  fe_debug.fe_debug_reg.reg = value;
1413  fe_debug.fe_debug_reg.read = 1;
1414 
1415  printf("WRITE: Type value (hex) i.g. 1A and press Enter:");
1416  value = get_user_hex_number();
1417 
1418  fe_debug.fe_debug_reg.read = 0;
1419  fe_debug.fe_debug_reg.value = (unsigned char)value;
1420 
1421  sang_if->set_fe_debug_mode(&fe_debug);
1422  }
1423  break;
1424 
1425  default:
1426  INFO_MAIN("Invalid command.\n");
1427  }
1428  }while(user_selection != 'q');
1429 
1430  stop(sang_if);
1431  cleanup(sang_if);
1432 
1433  return 0;
1434 }//main()
1435 
1436 static int set_port_configuration()
1437 {
1438  int rc = 0, user_selection;
1439  /* On hybrid cards such as B700, ports can be of different types -
1440  * some are Analog some Digital.
1441  * On non-hybrid cards such as A108, all ports are of the same
1442  * type - T1/E1. */
1443  int is_te1_port = 0, is_analog_port = 0, is_bri_port = 0, is_serial_port = 0, is_gsm_port=0;
1444  hardware_info_t hardware_info;
1445  port_cfg_t port_cfg;
1446 
1447  sangoma_port_configurator *sng_port_cfg_obj;
1448 
1449  sng_port_cfg_obj = new sangoma_port_configurator();
1450  if(sng_port_cfg_obj == NULL || sng_port_cfg_obj->init((unsigned short)program_settings.wanpipe_number)){
1451  ERR_MAIN("Failed to initialize 'sangoma_port_configurator'\n");
1452  return 2;
1453  }
1454 
1455  rc = sng_port_cfg_obj->get_hardware_info(&hardware_info);
1456 
1457  if(rc == SANG_STATUS_SUCCESS){
1458 
1459  INFO_MAIN("card_model : %s (%d)\n",
1460  SDLA_ADPTR_NAME(hardware_info.card_model), hardware_info.card_model);
1461  INFO_MAIN("firmware_version\t: 0x%02X\n", hardware_info.firmware_version);
1462  INFO_MAIN("pci_bus_number\t\t: %d\n", hardware_info.pci_bus_number);
1463  INFO_MAIN("pci_slot_number\t\t: %d\n", hardware_info.pci_slot_number);
1464  INFO_MAIN("max_hw_ec_chans\t\t: %d\n", hardware_info.max_hw_ec_chans);
1465  INFO_MAIN("port_number\t\t: %d\n", hardware_info.port_number);
1466 
1467  }else{
1468  ERR_MAIN("Failed to get hardware information\n");
1469  delete sng_port_cfg_obj;
1470  return 3;
1471  }
1472 
1473  // very important to zero out the configuration structure
1474  memset(&port_cfg, 0x00, sizeof(port_cfg_t));
1475 
1476  switch(hardware_info.card_model)
1477  {
1478  case A101_ADPTR_1TE1:
1479  case A101_ADPTR_2TE1:
1480  case A104_ADPTR_4TE1:
1481  case A108_ADPTR_8TE1:
1482  is_te1_port = 1;
1483  INFO_MAIN("T1/E1 Port on non-Hybrid Card (A10[1/2/4/8]).\n");
1484  break;
1485  case A200_ADPTR_ANALOG:
1486  case A400_ADPTR_ANALOG:
1487  case AFT_ADPTR_A600: //B600
1488  is_analog_port = 1;
1489  INFO_MAIN("Analog Port on non-Hybrid Card (A200/A400).\n");
1490  break;
1491  case AFT_ADPTR_ISDN:
1492  is_bri_port = 1;
1493  INFO_MAIN("BRI Port on non-Hybrid Card (A500).\n");
1494  break;
1495  case AFT_ADPTR_FLEXBRI:
1496  //B700, a hybrid card - may have both ISDN BRI and Analog ports
1497  if (hardware_info.bri_modtype == MOD_TYPE_NT ||
1498  hardware_info.bri_modtype == MOD_TYPE_TE) {
1499  is_bri_port = 1;
1500  INFO_MAIN("BRI Port on Hybrid Card.\n");
1501  } else {
1502  is_analog_port = 1;
1503  INFO_MAIN("Analog Port on Hybrid Card.\n");
1504  }
1505  break;
1506  case AFT_ADPTR_2SERIAL_V35X21: /* AFT-A142 2 Port V.35/X.21 board */
1507  case AFT_ADPTR_4SERIAL_V35X21: /* AFT-A144 4 Port V.35/X.21 board */
1508  case AFT_ADPTR_2SERIAL_RS232: /* AFT-A142 2 Port RS232 board */
1509  case AFT_ADPTR_4SERIAL_RS232: /* AFT-A144 4 Port RS232 board */
1510  is_serial_port = 1;
1511  INFO_MAIN("Serial Port on non-Hybrid Card (A14[2/4]).\n");
1512  break;
1513  case AFT_ADPTR_W400:
1514  is_gsm_port = 1;
1515  INFO_MAIN("GSM Port on GSM Card (W400).\n");
1516  break;
1517  default:
1518  INFO_MAIN("Warning: configuration of card model 0x%08X can not be changed!\n",
1519  hardware_info.card_model);
1520  break;
1521  }
1522 
1523 
1524  if (is_te1_port) {
1525  INFO_MAIN("\n");
1526  INFO_MAIN("Press 't' to set T1 configration.\n");
1527  INFO_MAIN("Press 'e' to set E1 configration.\n");
1528 try_again:
1529  user_selection = tolower(my_getch());
1530  switch(user_selection)
1531  {
1532  case 't'://T1
1533  rc=sng_port_cfg_obj->initialize_t1_tdm_span_voice_api_configration_structure(&port_cfg,&hardware_info,program_settings.wanpipe_number);
1534  break;
1535 
1536  case 'e'://E1
1537  rc=sng_port_cfg_obj->initialize_e1_tdm_span_voice_api_configration_structure(&port_cfg,&hardware_info,program_settings.wanpipe_number);
1538  break;
1539 
1540  case 'q'://quit the application
1541  rc = 1;
1542  break;
1543 
1544  default:
1545  INFO_MAIN("Invalid command %c.\n",user_selection);
1546  goto try_again;
1547 
1548  }//switch(user_selection)
1549  }//if(is_te1_port)
1550 
1551  if (is_analog_port) {
1552  //read current configuration:
1553  if(sng_port_cfg_obj->get_configration(&port_cfg)){
1554  rc = 1;
1555  }else{
1556  //print the current configuration:
1557  sng_port_cfg_obj->print_port_cfg_structure(&port_cfg);
1558 #if 0
1559  sng_port_cfg_obj->initialize_interface_mtu_mru(&port_cfg, 16, 16);
1560 #endif
1561 #if 0
1562  //as an EXAMPLE, enable Loop Current Monitoring for Analog FXO:
1563  rc=sng_port_cfg_obj->control_analog_rm_lcm(&port_cfg, 1);
1564 #endif
1565 #if 0
1566  //as an EXAMPLE, set Operation mode for FXO:
1567  rc=sng_port_cfg_obj->set_analog_opermode(&port_cfg, "TBR21");
1568 #endif
1569  }
1570  }//if(is_analog_port)
1571 
1572  if (is_bri_port) {
1573  rc=sng_port_cfg_obj->initialize_bri_tdm_span_voice_api_configration_structure(&port_cfg,&hardware_info,program_settings.wanpipe_number);
1574  }
1575 
1576  if (is_serial_port) {
1577  rc=sng_port_cfg_obj->initialize_serial_api_configration_structure(&port_cfg,&hardware_info,program_settings.wanpipe_number);
1578  }
1579 
1580  if (is_gsm_port) {
1581  rc=sng_port_cfg_obj->initialize_gsm_tdm_span_voice_api_configration_structure(&port_cfg,&hardware_info,program_settings.wanpipe_number);
1582  }
1583 
1584  if(!is_te1_port && !is_analog_port && !is_bri_port && !is_serial_port && !is_gsm_port){
1585  INFO_MAIN("Unsupported Card %d\n", hardware_info.card_model);
1586  rc = 1;
1587  }
1588 
1589  do{
1590  if (rc) {
1591  ERR_MAIN("Failed to Initialize Port Configuratoin structure!\n");
1592  break;
1593  }
1594 #if 1
1595  INFO_MAIN("Stopping PORT for re-configuration!\n");
1596  if ((rc = sng_port_cfg_obj->stop_port())) {
1597  ERR_MAIN("Failed to Stop Port! rc: %d\n", rc);
1598  break;
1599  }
1600 
1601  INFO_MAIN("Configuring PORT!\n");
1602  if ((rc = sng_port_cfg_obj->set_volatile_configration(&port_cfg))) {
1603  ERR_MAIN("Failed to Configure Port! rc: %d\n", rc);
1604  break;
1605  }
1606 
1607  INFO_MAIN("Starting PORT!\n");
1608  if ((rc = sng_port_cfg_obj->start_port())) {
1609  ERR_MAIN("Failed to Start Port! rc: %d\n", rc);
1610  break;
1611  }
1612 #endif
1613 #if 0
1614  //Optional step: the volatile configuration can be stored on the hard drive.
1615  if (rc = sng_port_cfg_obj->write_configration_on_persistent_storage(
1616  &port_cfg, &hardware_info, program_settings.wanpipe_number)) {
1617  ERR_MAIN("Failed to write configuration on persistant storage! rc: %d\n", rc);
1618  break;
1619  }
1620 #endif
1621  }while(0);
1622 
1623  if(sng_port_cfg_obj != NULL){
1624  delete sng_port_cfg_obj;
1625  }
1626 
1627  sangoma_msleep(2000);//wait 2 seconds for initialization to complete
1628 
1629  return rc;
1630 }
1631 
1632 
1633 #if USE_STELEPHONY_API
1634 static void FSKCallerIDEvent(void *callback_context,
1635  char * Name, char * CallerNumber,
1636  char * CalledNumber, char * DateTime)
1637 {
1638  //The "sangoma_interface" object was registered as the callback context in StelSetup() call.
1639  sangoma_interface *sang_if = (sangoma_interface*)callback_context;
1640 
1641  INFO_MAIN("\n%s: %s() - Start\n", sang_if->device_name, __FUNCTION__);
1642 
1643  if(Name){
1644  INFO_MAIN("Name: %s\n", Name);
1645 #if 0
1646  printf("caller name in SINGLE byte hex:\n");
1647  for(unsigned int ind = 0; ind < strlen(Name); ind++){
1648  printf("Name[%02d]: 0x%02X\n", ind, Name[ind]);
1649  }
1650  printf("\n");
1651 
1652  printf("caller name in DOUBLE byte (unicode) hex:\n");
1653  for(unsigned int ind = 0; ind < strlen(Name); ind += 2){
1654  printf("Name[%02d]: 0x%04X\n", ind, *(unsigned short*)&Name[ind]);
1655  }
1656 #endif
1657  printf("\n");
1658  }
1659 
1660 
1661  if(CallerNumber){
1662  INFO_MAIN("CallerNumber: %s\n", CallerNumber);
1663  }
1664  if(CalledNumber){
1665  INFO_MAIN("CalledNumber: %s\n", CalledNumber);
1666  }
1667  if(DateTime){
1668  INFO_MAIN("DateTime: %s\n", DateTime);
1669  }
1670 
1671  INFO_MAIN("Resetting FSK Caller ID\n");
1672  sang_if->resetFSKCID();//prepare for next FSK CID detection
1673 
1674  INFO_MAIN("%s() - End\n\n", __FUNCTION__);
1675 }
1676 
1677 static void DTMFEvent(void *callback_context, long Key)
1678 {
1679  //The "sangoma_interface" object was registered as the callback context in StelSetup() call.
1680  sangoma_interface *sang_if = (sangoma_interface*)callback_context;
1681 
1682  INFO_MAIN("\n%s: %s() - Start\n", sang_if->device_name, __FUNCTION__);
1683 
1684  INFO_MAIN("Key: %c\n", (char) Key);
1685 
1686  INFO_MAIN("%s() - End\n\n", __FUNCTION__);
1687 }
1688 
1689 static void Q931Event(void *callback_context, stelephony_q931_event *pQ931Event)
1690 {
1691  //The "sangoma_interface" object was registered as the callback context in StelSetup() call.
1692  sangoma_interface *sang_if = (sangoma_interface*)callback_context;
1693 
1694  INFO_MAIN("\n%s: %s() - Start\n", sang_if->device_name, __FUNCTION__);
1695 #if 0
1696  INFO_MAIN("\nFound %d bytes of data: ", pQ931Event->dataLength);
1697  for (int i=0; i < pQ931Event->dataLength;i++){
1698  INFO_MAIN("%02X ",pQ931Event->data[i]);
1699  }
1700  INFO_MAIN("\n");
1701 #endif
1702 
1703 
1704  INFO_MAIN("Message Received on: %02d/%02d/%02d @ %02d:%02d:%02d\n",pQ931Event->tv.wMonth,pQ931Event->tv.wDay,pQ931Event->tv.wYear,
1705  pQ931Event->tv.wHour,pQ931Event->tv.wMinute,pQ931Event->tv.wSecond);
1706 
1707  INFO_MAIN("Message Type is: %s\n",pQ931Event->msg_type);
1708  INFO_MAIN("Length of Call Reference Field is: %d\n", pQ931Event->len_callRef);
1709  INFO_MAIN("Message Call Reference is : 0X%s\n",pQ931Event->callRef);
1710 
1711  if (pQ931Event->cause_code > 0){
1712  INFO_MAIN("Cause code found = %d \n", pQ931Event->cause_code);
1713  }
1714 
1715  if (pQ931Event->chan > 0){
1716  INFO_MAIN("B-channel used = %d \n", pQ931Event->chan);
1717  }
1718 
1719  if (pQ931Event->calling_num_digits_count > 0 ){
1720  INFO_MAIN("Found %d digits for calling number \n", pQ931Event->calling_num_digits_count);
1721  INFO_MAIN("Presentation indicator is = %d \n",pQ931Event->calling_num_presentation);
1722  INFO_MAIN("Screening indicator is = %d \n",pQ931Event->calling_num_screening_ind);
1723  INFO_MAIN("Calling number is = %s\n",pQ931Event->calling_num_digits);
1724  }
1725 
1726  if (pQ931Event->called_num_digits_count > 0 ){
1727  INFO_MAIN("Found %d digits for called number \n", pQ931Event->called_num_digits_count);
1728  INFO_MAIN("Called number is = %s\n",pQ931Event->called_num_digits);
1729  }
1730 
1731  if (pQ931Event->rdnis_digits_count > 0 ){
1732  INFO_MAIN("Found %d digits for RDNIS\n", pQ931Event->rdnis_digits_count);
1733  INFO_MAIN("RDNIS is = %s\n",pQ931Event->rdnis_string);
1734  }
1735  //INFO_MAIN("%s() - End\n\n", __FUNCTION__);
1736 }
1737 
1738 /* A buffer containing DTMF digit was initialized. In this callback transmit the buffer
1739  by starting the SwDtmfTxThread */
1740 static void SwDtmfTransmit (void *callback_context, void *DtmfBuffer)
1741 {
1742  sangoma_interface *sang_if = (sangoma_interface*)callback_context;
1743  DBG_MAIN("%s(): %s:\n", __FUNCTION__, sang_if->device_name);
1744 
1745  /* DTMF buffer can be very big (long DTMF is not uncommon), we don't want to
1746  block the calling thread, so start a new thread to transmit SW-DTMF. */
1747  sang_if->CreateSwDtmfTxThread(DtmfBuffer);
1748 }
1749 
1750 /* A buffer containing FSK CID was initialized. In this callback transmit the buffer. */
1751 static void FSKCallerIDTransmit (void *callback_context, void *FskCidBuffer)
1752 {
1753  sangoma_interface *sang_if = (sangoma_interface*)callback_context;
1754  DBG_MAIN("%s(): %s:\n", __FUNCTION__, sang_if->device_name);
1755 
1756  /* FSK CID buffer can be big (~8000 bytes), we don't want to block the calling thread,
1757  so start a new thread to transmit FSK CID. */
1758  sang_if->CreateFskCidTxThread(FskCidBuffer);
1759 }
1760 
1761 #if 0
1762 #warning "REMOVE LATER"
1763 int slin2ulaw(void* data, size_t max, size_t *datalen)
1764 {
1765  int16_t sln_buf[512] = {0}, *sln = sln_buf;
1766  uint8_t *lp = (uint8_t*)data;
1767  uint32_t i;
1768  size_t len = *datalen;
1769 
1770  if (max > len) {
1771  max = len;
1772  }
1773 
1774  memcpy(sln, data, max);
1775 
1776  for(i = 0; i < max; i++) {
1777  *lp++ = linear_to_ulaw(*sln++);
1778  }
1779 
1780  *datalen = max / 2;
1781 
1782  return 0;
1783 }
1784 #endif
1785 
1786 #endif /* USE_STELEPHONY_API */
1787 
1788 #if 0
1789 LONG Win32FaultHandler(struct _EXCEPTION_POINTERS * ExInfo)
1790 
1791 {
1792  char *FaultTx = "";
1793  switch(ExInfo->ExceptionRecord->ExceptionCode)
1794  {
1795  case EXCEPTION_ACCESS_VIOLATION:
1796  FaultTx = "ACCESS VIOLATION";
1797  break;
1798  case EXCEPTION_DATATYPE_MISALIGNMENT:
1799  FaultTx = "DATATYPE MISALIGNMENT";
1800  break;
1801  case EXCEPTION_FLT_DIVIDE_BY_ZERO:
1802  FaultTx = "FLT DIVIDE BY ZERO";
1803  break;
1804  default: FaultTx = "(unknown)";
1805  break;
1806  }
1807 
1808  FILE *sgLogFile = fopen("Win32Fault.log", "w");
1809  int wsFault = ExInfo->ExceptionRecord->ExceptionCode;
1810  PVOID CodeAddress = ExInfo->ExceptionRecord->ExceptionAddress;
1811 
1812  sgLogFile = fopen("Win32Fault.log", "w");
1813  if(sgLogFile != NULL)
1814  {
1815  fprintf(sgLogFile, "****************************************************\n");
1816  fprintf(sgLogFile, "*** A Program Fault occurred:\n");
1817  fprintf(sgLogFile, "*** Error code %08X: %s\n", wsFault, FaultTx);
1818  fprintf(sgLogFile, "****************************************************\n");
1819  fprintf(sgLogFile, "*** Address: %08X\n", (int)CodeAdress);
1820  fprintf(sgLogFile, "*** Flags: %08X\n",
1821  ExInfo->ExceptionRecord->ExceptionFlags);
1822  LogStackFrames(CodeAddress, (char *)ExInfo->ContextRecord->Ebp);
1823  fclose(sgLogFile);
1824  }
1825  /*if(want to continue)
1826  {
1827  ExInfo->ContextRecord->Eip++;
1828  return EXCEPTION_CONTINUE_EXECUTION;
1829  }
1830  */
1831  return EXCEPTION_EXECUTE_HANDLER;
1832 }
1833 #endif
void cleanup(void)
Protperly shutdown single device.
Definition: sample.c:697
Sangoma Interface Class that deals with span/chan IO (read/write/events)
u_int8_t operation_status
sangoma_interface * init(int wanpipe_number, int interface_number)
Create a sangoma_interface class and setup callback functions.
Definition: sample.cpp:111
Used with Sample.cpp Code.
#define __cdecl
Ported from Windows.
Definition: libsangoma.h:241
#define _stricmp
_stricmp type mapped to _stricmp, Ported from Windows
Definition: libsangoma.h:254
#define sangoma_msleep(x)
milisecond sleep function
Definition: libsangoma.h:251
void PrintRxData(wp_api_hdr_t *hdr, void *pdata)
Debug function used to print Rx Data.
Definition: sample.cpp:177
TDM API channel statistics.
Wanpipe API Event Structure.
int start(sangoma_interface *sang_if)
Run the main sangoma interface hanlder code.
Definition: sample.cpp:153
u_int32_t time_stamp_usec
#define WP_API_EVENT_POLARITY_REVERSE_DECODE(polarity_reverse)
Print out the Polarity state.
u_int32_t time_stamp_sec
int __cdecl main(int argc, char *argv[])
Main function that starts the sample code.
Definition: sample.c:1018
u_int32_t time_stamp_usec
void stop(sangoma_interface *sang_if)
Stop the Sangoma Interface Object.
Definition: sample.cpp:165
u_int32_t time_stamp_sec
Wanpipe API Header Structure.
int transmit(wp_api_hdr_t *hdr, void *data)
u_int16_t data_length
int tx_file(sangoma_interface *sang_if)
Transmit a file on a sangoma interface / device.
Definition: sample.cpp:385
#define WAN_BRI_BCHAN1
BRI Channel 1.
#define sangoma_ctime(time)
Convert a time value to a string.
Definition: libsangoma.h:291