946 lines
28 KiB
Plaintext
946 lines
28 KiB
Plaintext
/******************************************************************************//**
|
|
* \file sample.c
|
|
* \brief WANPIPE(tm) API C Sample Code
|
|
*
|
|
* Authors: David Rokhvarg <davidr@sangoma.com>
|
|
* Nenad Corbic <ncorbic@sangoma.com>
|
|
*
|
|
* Copyright (c) 2007 - 08, Sangoma Technologies
|
|
* All rights reserved.
|
|
*
|
|
* * Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of the Sangoma Technologies nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY Sangoma Technologies ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL Sangoma Technologies BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* ===============================================================================
|
|
*
|
|
*/
|
|
|
|
#include "libsangoma.h"
|
|
#include "lib_api.h"
|
|
|
|
static u_int32_t poll_events_bitmap = 0;
|
|
|
|
/*!
|
|
\def TEST_NUMBER_OF_OBJECTS
|
|
\brief Number of wait objects to define in object array.
|
|
|
|
Objects are used to wait on file descripotrs.
|
|
Usually there is one wait object per file descriptor.
|
|
|
|
In this example there is a single file descriptor and a
|
|
single wait object.
|
|
*/
|
|
#define TEST_NUMBER_OF_OBJECTS 1
|
|
|
|
static sangoma_wait_obj_t *sangoma_wait_objects[TEST_NUMBER_OF_OBJECTS];
|
|
|
|
/* This example application has only a single execution thread - it is safe
|
|
* to use a global buffer for received data and for data to be transmitted. */
|
|
static unsigned char rxdata[MAX_NO_DATA_BYTES_IN_FRAME];
|
|
static unsigned char txdata[MAX_NO_DATA_BYTES_IN_FRAME];
|
|
|
|
typedef struct sangoma_chan {
|
|
int spanno;
|
|
int channo;
|
|
} sangoma_chan_t;
|
|
sangoma_chan_t sangoma_channels[TEST_NUMBER_OF_OBJECTS];
|
|
|
|
/* Warning: non-thread safe globals. Ok for this single-thread example but not in production. */
|
|
unsigned char rx_rbs_bits = WAN_RBS_SIG_A;
|
|
FILE *pRxFile;
|
|
int application_termination_flag = 0;
|
|
|
|
/*****************************************************************
|
|
* Prototypes
|
|
*****************************************************************/
|
|
|
|
int __cdecl main(int argc, char* argv[]);
|
|
int open_sangoma_device(void);
|
|
void handle_span_chan(int open_device_counter);
|
|
int handle_tdm_event(uint32_t dev_index);
|
|
int handle_data(uint32_t dev_index, int flags_out);
|
|
int read_data(uint32_t dev_index, wp_api_hdr_t *rx_hdr, void *rx_buffer, int rx_buffer_length);
|
|
int write_data(uint32_t dev_index, wp_api_hdr_t *tx_hdr, void *tx_buffer, int tx_len);
|
|
int dtmf_event(sng_fd_t fd,unsigned char digit,unsigned char type,unsigned char port);
|
|
int rbs_event(sng_fd_t fd,unsigned char rbs_bits);
|
|
int rxhook_event(sng_fd_t fd,unsigned char hook_state);
|
|
int rxring_event(sng_fd_t fd,unsigned char ring_state);
|
|
int ringtrip_event (sng_fd_t fd, unsigned char ring_state);
|
|
int write_data_to_file(unsigned char *data, unsigned int data_length);
|
|
int sangoma_print_stats(sng_fd_t sangoma_dev);
|
|
void cleanup(void);
|
|
|
|
#ifdef __WINDOWS__
|
|
BOOL WINAPI TerminateHandler(DWORD dwCtrlType);
|
|
#else
|
|
void TerminateHandler(int);
|
|
#endif
|
|
|
|
/*****************************************************************
|
|
* General Functions
|
|
*****************************************************************/
|
|
|
|
/*!
|
|
\fn void print_rx_data(unsigned char *data, int datalen)
|
|
\brief Prints the contents of data packet
|
|
\param data pointer to data buffer
|
|
\param datalen size of data buffer
|
|
\return void
|
|
*/
|
|
void print_rxdata(unsigned char *data, int datalen, wp_api_hdr_t *hdr); /* dont remove prototype, gcc complains */
|
|
void print_rxdata(unsigned char *data, int datalen, wp_api_hdr_t *hdr)
|
|
{
|
|
int i;
|
|
int err=0;
|
|
|
|
<<<<<<< .mine
|
|
printf("Data: (Len=%i,Errs=%i)\n",datalen,hdr->wp_api_rx_hdr_errors);
|
|
=======
|
|
#ifdef WP_API_FEATURE_RX_TX_ERRS
|
|
err=hdr->wp_api_rx_hdr_errors;
|
|
#endif
|
|
printf("Data: (Len=%i,Errs=%i)\n",datalen,err);
|
|
>>>>>>> .r292
|
|
for(i = 0; i < datalen; i++) {
|
|
if((i % 20 == 0)){
|
|
if(i){
|
|
printf("\n");
|
|
}
|
|
}
|
|
printf("%02X ", data[i]);
|
|
#if 0
|
|
/* don't print too much!! */
|
|
if(i > 100){
|
|
printf("...\n");
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
int sangoma_print_stats(sng_fd_t sangoma_dev)
|
|
{
|
|
int err;
|
|
unsigned char firm_ver, cpld_ver;
|
|
wanpipe_api_t wp_api;
|
|
wanpipe_chan_stats_t stats_str;
|
|
wanpipe_chan_stats_t *stats=&stats_str;
|
|
memset(&wp_api,0,sizeof(wp_api));
|
|
|
|
|
|
err=sangoma_get_stats(sangoma_dev, &wp_api, stats);
|
|
if (err) {
|
|
printf("sangoma_get_stats(() failed (err: %d (0x%X))!\n", err, err);
|
|
return 1;
|
|
}
|
|
|
|
printf( "******* OPERATIONAL_STATS *******\n");
|
|
|
|
printf("\trx_packets\t: %u\n", stats->rx_packets);
|
|
printf("\ttx_packets\t: %u\n", stats->tx_packets);
|
|
printf("\trx_bytes\t: %u\n", stats->rx_bytes);
|
|
printf("\ttx_bytes\t: %u\n", stats->tx_bytes);
|
|
printf("\trx_errors\t: %u\n", stats->rx_errors); //Total number of Rx errors
|
|
printf("\ttx_errors\t: %u\n", stats->tx_errors); //Total number of Tx errors
|
|
printf("\trx_dropped\t: %u\n", stats->rx_dropped);
|
|
printf("\ttx_dropped\t: %u\n", stats->tx_dropped);
|
|
printf("\tmulticast\t: %u\n", stats->multicast);
|
|
printf("\tcollisions\t: %u\n", stats->collisions);
|
|
|
|
printf("\trx_length_errors: %u\n", stats->rx_length_errors);
|
|
printf("\trx_over_errors\t: %u\n", stats->rx_over_errors);
|
|
printf("\trx_crc_errors\t: %u\n", stats->rx_crc_errors); //HDLC CRC mismatch
|
|
printf("\trx_frame_errors\t: %u\n", stats->rx_frame_errors);//HDLC "abort" occured
|
|
printf("\trx_fifo_errors\t: %u\n", stats->rx_fifo_errors);
|
|
printf("\trx_missed_errors: %u\n", stats->rx_missed_errors);
|
|
|
|
printf("\ttx_aborted_errors: %u\n", stats->tx_aborted_errors);
|
|
printf("\tTx Idle Data\t: %u\n", stats->tx_carrier_errors);
|
|
|
|
printf("\ttx_fifo_errors\t: %u\n", stats->tx_fifo_errors);
|
|
printf("\ttx_heartbeat_errors: %u\n", stats->tx_heartbeat_errors);
|
|
printf("\ttx_window_errors: %u\n", stats->tx_window_errors);
|
|
|
|
printf("\n\ttx_packets_in_q: %u\n", stats->current_number_of_frames_in_tx_queue);
|
|
printf("\ttx_queue_size: %u\n", stats->max_tx_queue_length);
|
|
|
|
printf("\n\trx_packets_in_q: %u\n", stats->current_number_of_frames_in_rx_queue);
|
|
printf("\trx_queue_size: %u\n", stats->max_rx_queue_length);
|
|
|
|
printf("\n\trx_events_in_q: %u\n", stats->current_number_of_events_in_event_queue);
|
|
printf("\trx_event_queue_size: %u\n", stats->max_event_queue_length);
|
|
printf("\trx_events: %u\n", stats->rx_events);
|
|
printf("\trx_events_dropped: %u\n", stats->rx_events_dropped);
|
|
|
|
printf("\tHWEC tone (DTMF) events counter: %u\n", stats->rx_events_tone);
|
|
printf( "*********************************\n");
|
|
|
|
SANGOMA_INIT_TDM_API_CMD(wp_api);
|
|
err=sangoma_get_driver_version(sangoma_dev,&wp_api, NULL);
|
|
if (err) {
|
|
return 1;
|
|
}
|
|
printf("\tDriver Version: %u.%u.%u.%u\n",
|
|
wp_api.wp_cmd.version.major,
|
|
wp_api.wp_cmd.version.minor,
|
|
wp_api.wp_cmd.version.minor1,
|
|
wp_api.wp_cmd.version.minor2);
|
|
|
|
SANGOMA_INIT_TDM_API_CMD(wp_api);
|
|
err=sangoma_get_firmware_version(sangoma_dev, &wp_api, &firm_ver);
|
|
if (err) {
|
|
return 1;
|
|
}
|
|
printf("\tFirmware Version: %X\n",
|
|
firm_ver);
|
|
|
|
SANGOMA_INIT_TDM_API_CMD(wp_api);
|
|
err=sangoma_get_cpld_version(sangoma_dev, &wp_api, &cpld_ver);
|
|
if (err) {
|
|
return 1;
|
|
}
|
|
printf("\tCPLD Version: %X\n",
|
|
cpld_ver);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\fn int read_data(uint32_t dev_index)
|
|
\brief Read data buffer from a device
|
|
\param dev_index device index number associated with device file descriptor
|
|
\param rx_hdr pointer to api header
|
|
\param rx_buffer pointer to a buffer where recived data will be stored
|
|
\param rx_buffer_length maximum length of rx_buffer
|
|
\return 0 - Ok otherwise Error
|
|
*/
|
|
int read_data(uint32_t dev_index, wp_api_hdr_t *rx_hdr, void *rx_buffer, int rx_buffer_length)
|
|
{
|
|
sng_fd_t dev_fd = sangoma_wait_obj_get_fd(sangoma_wait_objects[dev_index]);
|
|
sangoma_chan_t *chan = sangoma_wait_obj_get_context(sangoma_wait_objects[dev_index]);
|
|
int Rx_lgth = 0;
|
|
static int Rx_count= 0;
|
|
wanpipe_api_t tdm_api;
|
|
|
|
memset(&tdm_api, 0x00, sizeof(tdm_api));
|
|
memset(rx_hdr, 0, sizeof(wp_api_hdr_t));
|
|
|
|
/* read the message */
|
|
Rx_lgth = sangoma_readmsg(
|
|
dev_fd,
|
|
rx_hdr, /* header buffer */
|
|
sizeof(wp_api_hdr_t), /* header size */
|
|
rx_buffer, /* data buffer */
|
|
rx_buffer_length, /* data BUFFER size */
|
|
0);
|
|
if(Rx_lgth <= 0) {
|
|
printf("Span: %d, Chan: %d: Error receiving data!\n",
|
|
chan->spanno, chan->channo);
|
|
return 1;
|
|
}
|
|
|
|
|
|
<<<<<<< .mine
|
|
if (rx_hdr->wp_api_rx_hdr_error_map) {
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_FIFO_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx fifo error\n");
|
|
}
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_CRC_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx crc error\n");
|
|
}
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_ABORT_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx abort error\n");
|
|
}
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_FRAME_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx framing error\n");
|
|
}
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_DMA_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx dma error\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
=======
|
|
#ifdef WP_API_FEATURE_RX_TX_ERRS
|
|
if (rx_hdr->wp_api_rx_hdr_error_map) {
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_FIFO_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx fifo error 0x%02X\n",chan->spanno,chan->channo,rx_hdr->wp_api_rx_hdr_error_map);
|
|
}
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_CRC_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx crc error 0x%02X\n",chan->spanno,chan->channo,rx_hdr->wp_api_rx_hdr_error_map);
|
|
}
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_ABORT_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx abort error 0x%02X\n",chan->spanno,chan->channo,rx_hdr->wp_api_rx_hdr_error_map);
|
|
}
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_FRAME_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx framing error 0x%02X\n",chan->spanno,chan->channo,rx_hdr->wp_api_rx_hdr_error_map);
|
|
}
|
|
if (rx_hdr->wp_api_rx_hdr_error_map & 1<<WP_DMA_ERROR_BIT) {
|
|
printf("Span: %d, Chan: %d rx dma error 0x%02X\n",chan->spanno,chan->channo,rx_hdr->wp_api_rx_hdr_error_map);
|
|
}
|
|
//return 1;
|
|
}
|
|
#endif
|
|
|
|
>>>>>>> .r292
|
|
Rx_count++;
|
|
|
|
if (verbose){
|
|
print_rxdata(rx_buffer, Rx_lgth,rx_hdr);
|
|
}
|
|
|
|
if (stats_period && Rx_count % stats_period == 0) {
|
|
sangoma_print_stats(dev_fd);
|
|
}
|
|
|
|
/* use Rx_counter as "write" events trigger: */
|
|
if(rbs_events == 1 && (Rx_count % 400) == 0){
|
|
/* bitmap - set as needed: WAN_RBS_SIG_A | WAN_RBS_SIG_B | WAN_RBS_SIG_C | WAN_RBS_SIG_D;
|
|
|
|
In this example make bits A and B to change each time,
|
|
so it's easy to see the change on the receiving side.
|
|
*/
|
|
if(rx_rbs_bits == WAN_RBS_SIG_A){
|
|
rx_rbs_bits = WAN_RBS_SIG_B;
|
|
}else{
|
|
rx_rbs_bits = WAN_RBS_SIG_A;
|
|
}
|
|
printf("Writing RBS bits (0x%X)...\n", rx_rbs_bits);
|
|
sangoma_tdm_write_rbs(dev_fd, &tdm_api,
|
|
chan->channo,
|
|
rx_rbs_bits);
|
|
}
|
|
|
|
/* if user needs Rx data to be written into a file: */
|
|
if(files_used & RX_FILE_USED){
|
|
write_data_to_file(rx_buffer, Rx_lgth);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\fn int write_data(uint32_t dev_index, wp_api_hdr_t *tx_hdr, void *tx_data, int tx_len)
|
|
\brief Transmit a data buffer to a device.
|
|
\param dev_index device index number associated with device file descriptor
|
|
\param tx_hdr pointer to a wp_api_hdr_t
|
|
\param tx_data pointer to a data buffer
|
|
\param tx_len tx data buffer len
|
|
\return 0 - Ok otherwise Error
|
|
*/
|
|
int write_data(uint32_t dev_index, wp_api_hdr_t *tx_hdr, void *tx_buffer, int tx_len)
|
|
{
|
|
sng_fd_t dev_fd = sangoma_wait_obj_get_fd(sangoma_wait_objects[dev_index]);
|
|
sangoma_chan_t *chan = sangoma_wait_obj_get_context(sangoma_wait_objects[dev_index]);
|
|
int err;
|
|
static int Tx_count = 0;
|
|
|
|
if (hdlc_repeat) {
|
|
tx_hdr->wp_api_tx_hdr_hdlc_rpt_len=4;
|
|
memset(tx_hdr->wp_api_tx_hdr_hdlc_rpt_data,Tx_count,4);
|
|
}
|
|
|
|
/* write a message */
|
|
err = sangoma_writemsg(
|
|
dev_fd,
|
|
tx_hdr, /* header buffer */
|
|
sizeof(wp_api_hdr_t), /* header size */
|
|
tx_buffer, /* data buffer */
|
|
tx_len, /* DATA size */
|
|
0);
|
|
|
|
if (err <= 0){
|
|
printf("Span: %d, Chan: %d: Failed to send!\n",
|
|
chan->spanno,
|
|
chan->channo);
|
|
return -1;
|
|
}
|
|
|
|
Tx_count++;
|
|
if (verbose){
|
|
printf("Packet sent: counter: %i, len: %i, errors %i\n", Tx_count, err, tx_hdr->wp_api_tx_hdr_errors);
|
|
}else{
|
|
if(Tx_count && (!(Tx_count % 1000))){
|
|
printf("Packet sent: counter: %i, len: %i\n", Tx_count, err);
|
|
}
|
|
}
|
|
|
|
#if 1
|
|
if(tx_cnt && Tx_count >= tx_cnt){
|
|
write_enable=0;
|
|
printf("Disabling POLLOUT...\n");
|
|
/* No need for POLLOUT, turn it off!! If not turned off, and we
|
|
* have nothing for transmission, sangoma_socket_waitfor() will return
|
|
* immediately, creating a busy loop. */
|
|
//sangoma_wait_objects[dev_index].flags_in &= (~POLLOUT);
|
|
return 1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\fn int handle_data(uint32_t dev_index, int flags_out)
|
|
\brief Read data buffer from the device and transmit it back down.
|
|
\param dev_index device index number associated with device file descriptor
|
|
\return 0 - Ok otherwise Error
|
|
|
|
Read data buffer from a device.
|
|
*/
|
|
int handle_data(uint32_t dev_index, int flags_out)
|
|
{
|
|
wp_api_hdr_t rxhdr;
|
|
int err=0;
|
|
|
|
memset(&rxhdr, 0, sizeof(rxhdr));
|
|
|
|
#if 0
|
|
printf("%s(): span: %d, chan: %d\n", __FUNCTION__,
|
|
sangoma_wait_objects[dev_index].span, sangoma_wait_objects[dev_index].chan);
|
|
#endif
|
|
|
|
if(flags_out & POLLIN){
|
|
if(read_data(dev_index, &rxhdr, rxdata, MAX_NO_DATA_BYTES_IN_FRAME) == 0){
|
|
if(rx2tx){
|
|
/* Send back received data (create a "software loopback"), just a test. */
|
|
return write_data(dev_index, &rxhdr, rxdata,rxhdr.data_length);
|
|
}
|
|
}
|
|
}
|
|
|
|
if( (flags_out & POLLOUT) && write_enable ){
|
|
|
|
wp_api_hdr_t txhdr;
|
|
static unsigned char tx_test_byte = 0;
|
|
|
|
memset(&txhdr, 0, sizeof(txhdr));
|
|
txhdr.data_length = (unsigned short)tx_size;/* use '-txsize' command line option to change 'tx_size' */
|
|
|
|
/* set data which will be transmitted */
|
|
memset(txdata, tx_test_byte, txhdr.data_length);
|
|
|
|
err = write_data(dev_index, &txhdr, txdata, tx_size);
|
|
if (err== 0) {
|
|
tx_test_byte++;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/*!
|
|
\fn int decode_api_event (wp_api_event_t *wp_tdm_api_event)
|
|
\brief Handle API Event
|
|
\param wp_tdm_api_event
|
|
*/
|
|
static void decode_api_event(wp_api_event_t *wp_tdm_api_event)
|
|
{
|
|
printf("%s(): span: %d, chan: %d\n", __FUNCTION__,
|
|
wp_tdm_api_event->span, wp_tdm_api_event->channel);
|
|
|
|
switch(wp_tdm_api_event->wp_api_event_type)
|
|
{
|
|
case WP_API_EVENT_DTMF:/* DTMF detected by Hardware */
|
|
printf("DTMF Event: Channel: %d, Digit: %c (Port: %s, Type:%s)!\n",
|
|
wp_tdm_api_event->channel,
|
|
wp_tdm_api_event->wp_api_event_dtmf_digit,
|
|
(wp_tdm_api_event->wp_api_event_dtmf_port == WAN_EC_CHANNEL_PORT_ROUT)?"ROUT":"SOUT",
|
|
(wp_tdm_api_event->wp_api_event_dtmf_type == WAN_EC_TONE_PRESENT)?"PRESENT":"STOP");
|
|
break;
|
|
|
|
case WP_API_EVENT_RXHOOK:
|
|
printf("RXHOOK Event: Channel: %d, %s! (0x%X)\n",
|
|
wp_tdm_api_event->channel,
|
|
WAN_EVENT_RXHOOK_DECODE(wp_tdm_api_event->wp_api_event_hook_state),
|
|
wp_tdm_api_event->wp_api_event_hook_state);
|
|
break;
|
|
|
|
case WP_API_EVENT_RING_DETECT:
|
|
printf("RING Event: %s! (0x%X)\n",
|
|
WAN_EVENT_RING_DECODE(wp_tdm_api_event->wp_api_event_ring_state),
|
|
wp_tdm_api_event->wp_api_event_ring_state);
|
|
break;
|
|
|
|
case WP_API_EVENT_RING_TRIP_DETECT:
|
|
printf("RING TRIP Event: %s! (0x%X)\n",
|
|
WAN_EVENT_RING_TRIP_DECODE(wp_tdm_api_event->wp_api_event_ring_state),
|
|
wp_tdm_api_event->wp_api_event_ring_state);
|
|
break;
|
|
|
|
case WP_API_EVENT_RBS:
|
|
printf("RBS Event: Channel: %d, 0x%X!\n",
|
|
wp_tdm_api_event->channel,
|
|
wp_tdm_api_event->wp_api_event_rbs_bits);
|
|
printf( "RX RBS: A:%1d B:%1d C:%1d D:%1d\n",
|
|
(wp_tdm_api_event->wp_api_event_rbs_bits & WAN_RBS_SIG_A) ? 1 : 0,
|
|
(wp_tdm_api_event->wp_api_event_rbs_bits & WAN_RBS_SIG_B) ? 1 : 0,
|
|
(wp_tdm_api_event->wp_api_event_rbs_bits & WAN_RBS_SIG_C) ? 1 : 0,
|
|
(wp_tdm_api_event->wp_api_event_rbs_bits & WAN_RBS_SIG_D) ? 1 : 0);
|
|
break;
|
|
|
|
case WP_API_EVENT_LINK_STATUS:
|
|
printf("Link Status Event: %s! (0x%X)\n",
|
|
WAN_EVENT_LINK_STATUS_DECODE(wp_tdm_api_event->wp_api_event_link_status),
|
|
wp_tdm_api_event->wp_api_event_link_status);
|
|
break;
|
|
|
|
case WP_API_EVENT_ALARM:
|
|
printf("New Alarm State: %s! (0x%X)\n", (wp_tdm_api_event->wp_api_event_alarm == 0?"Off":"On"),
|
|
wp_tdm_api_event->wp_api_event_alarm);
|
|
break;
|
|
|
|
case WP_API_EVENT_POLARITY_REVERSE:
|
|
printf("Polarity Reversal Event : %s! (0x%X)\n",
|
|
WP_API_EVENT_POLARITY_REVERSE_DECODE(wp_tdm_api_event->wp_api_event_polarity_reverse),
|
|
wp_tdm_api_event->wp_api_event_polarity_reverse);
|
|
break;
|
|
|
|
default:
|
|
printf("Unknown TDM API Event: %d\n", wp_tdm_api_event->wp_api_event_type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\fn int handle_tdm_event(uint32_t dev_index)
|
|
\brief Read Event buffer from the device
|
|
\param dev_index device index number associated with device file descriptor
|
|
\return 0 - Ok otherwise Error
|
|
|
|
An EVENT has occoured. Execute a system call to read the EVENT
|
|
on a device.
|
|
*/
|
|
int handle_tdm_event(uint32_t dev_index)
|
|
{
|
|
wanpipe_api_t tdm_api;
|
|
sng_fd_t dev_fd = sangoma_wait_obj_get_fd(sangoma_wait_objects[dev_index]);
|
|
|
|
#if 0
|
|
printf("%s(): dev_index: %d, dev_fd: 0x%p\n", __FUNCTION__, dev_index, dev_fd);
|
|
#endif
|
|
|
|
memset(&tdm_api, 0x00, sizeof(tdm_api));
|
|
|
|
if(sangoma_read_event(dev_fd, &tdm_api)){
|
|
return 1;
|
|
}
|
|
|
|
decode_api_event(&tdm_api.wp_cmd.event);
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\fn void handle_span_chan(int open_device_counter)
|
|
\brief Write data buffer into a file
|
|
\param open_device_counter number of opened devices
|
|
\return void
|
|
|
|
This function will wait on all opened devices.
|
|
This example will wait for RX and EVENT signals.
|
|
In case of POLLIN - rx data available
|
|
In case of POLLPRI - event is available
|
|
*/
|
|
void handle_span_chan(int open_device_counter)
|
|
{
|
|
int iResult, i;
|
|
u_int32_t input_flags[TEST_NUMBER_OF_OBJECTS];
|
|
u_int32_t output_flags[TEST_NUMBER_OF_OBJECTS];
|
|
|
|
printf("\n\nSpan/Chan Handler: RxEnable=%s, TxEnable=%s, TxCnt=%i, TxLen=%i, rx2tx=%s\n",
|
|
(read_enable? "Yes":"No"), (write_enable?"Yes":"No"),tx_cnt,tx_size, (rx2tx?"Yes":"No"));
|
|
|
|
for (i = 0; i < open_device_counter; i++) {
|
|
input_flags[i] = poll_events_bitmap;
|
|
}
|
|
|
|
/* Main Rx/Tx/Event loop */
|
|
while(!application_termination_flag)
|
|
{
|
|
iResult = sangoma_waitfor_many(sangoma_wait_objects,
|
|
input_flags,
|
|
output_flags,
|
|
open_device_counter /* number of wait objects */,
|
|
5000 /* wait timeout, in milliseconds */);
|
|
switch(iResult)
|
|
{
|
|
case SANG_STATUS_APIPOLL_TIMEOUT:
|
|
/* timeout (not an error) */
|
|
{
|
|
sng_fd_t dev_fd = sangoma_wait_obj_get_fd(sangoma_wait_objects[0]);
|
|
sangoma_print_stats(dev_fd);
|
|
}
|
|
printf("Timeout\n");
|
|
continue;
|
|
|
|
case SANG_STATUS_SUCCESS:
|
|
for(i = 0; i < open_device_counter; i++){
|
|
|
|
/* a wait object was signaled */
|
|
if(output_flags[i] & POLLPRI){
|
|
/* got tdm api event */
|
|
if(handle_tdm_event(i)){
|
|
printf("Error in handle_tdm_event()!\n");
|
|
application_termination_flag=1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(output_flags[i] & (POLLIN | POLLOUT)){
|
|
/* rx data OR a free tx buffer available */
|
|
if(handle_data(i, output_flags[i])){
|
|
printf("Error in handle_data()!\n");
|
|
//application_termination_flag=1;
|
|
break;
|
|
}
|
|
}
|
|
}/* for() */
|
|
break;
|
|
|
|
default:
|
|
/* error */
|
|
printf("Error: iResult: %s (%d)\n", SDLA_DECODE_SANG_STATUS(iResult), iResult);
|
|
return;
|
|
}
|
|
|
|
}/* while() */
|
|
}
|
|
|
|
/*!
|
|
\fn int write_data_to_file(unsigned char *data, unsigned int data_length)
|
|
\brief Write data buffer into a file
|
|
\param data data buffer
|
|
\param data_length length of a data buffer
|
|
\return data_length = ok otherwise error
|
|
|
|
*/
|
|
int write_data_to_file(unsigned char *data, unsigned int data_length)
|
|
{
|
|
if(pRxFile == NULL){
|
|
return 1;
|
|
}
|
|
|
|
return fwrite(data, 1, data_length, pRxFile);
|
|
}
|
|
|
|
#ifdef __WINDOWS__
|
|
/*
|
|
* TerminateHandler() - this handler is called by the system whenever user tries to terminate
|
|
* the process with Ctrl+C, Ctrl+Break or closes the console window.
|
|
* Perform a clean-up here.
|
|
*/
|
|
BOOL TerminateHandler(DWORD dwCtrlType)
|
|
{
|
|
printf("\nProcess terminated by user request.\n");
|
|
application_termination_flag = 1;
|
|
/* do the cleanup before exiting: */
|
|
cleanup();
|
|
/* return FALSE so the system will call the dafult handler which will terminate the process. */
|
|
return FALSE;
|
|
}
|
|
#else
|
|
/*!
|
|
\fn void TerminateHandler (int sig)
|
|
\brief Signal handler for graceful shutdown
|
|
\param sig signal
|
|
*/
|
|
void TerminateHandler (int sig)
|
|
{
|
|
printf("\nProcess terminated by user request.\n");
|
|
application_termination_flag = 1;
|
|
/* do the cleanup before exiting: */
|
|
cleanup();
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*!
|
|
\fn void cleanup()
|
|
\brief Protperly shutdown single device
|
|
\param dev_no device index number
|
|
\return void
|
|
|
|
*/
|
|
void cleanup()
|
|
{
|
|
int dev_no;
|
|
sng_fd_t fd;
|
|
sangoma_chan_t *chan;
|
|
sangoma_wait_obj_t *sng_wait_object;
|
|
wanpipe_api_t tdm_api;
|
|
|
|
/* do the cleanup before exiting: */
|
|
for(dev_no = 0; dev_no < TEST_NUMBER_OF_OBJECTS; dev_no++){
|
|
|
|
sng_wait_object = sangoma_wait_objects[dev_no];
|
|
if(!sng_wait_object){
|
|
continue;
|
|
}
|
|
chan = sangoma_wait_obj_get_context(sng_wait_object);
|
|
printf("%s(): span: %d, chan: %d ...\n", __FUNCTION__,
|
|
chan->channo,
|
|
chan->spanno);
|
|
|
|
fd = sangoma_wait_obj_get_fd(sng_wait_object);
|
|
memset(&tdm_api, 0x00, sizeof(tdm_api));
|
|
|
|
if(dtmf_enable_octasic == 1){
|
|
/* Disable dtmf detection on Octasic chip */
|
|
sangoma_tdm_disable_dtmf_events(fd, &tdm_api);
|
|
}
|
|
|
|
if(dtmf_enable_remora == 1){
|
|
/* Disable dtmf detection on Sangoma's Remora SLIC chip */
|
|
sangoma_tdm_disable_rm_dtmf_events(fd, &tdm_api);
|
|
}
|
|
|
|
if(remora_hook == 1){
|
|
sangoma_tdm_disable_rxhook_events(fd, &tdm_api);
|
|
}
|
|
|
|
if(rbs_events == 1){
|
|
sangoma_tdm_disable_rbs_events(fd, &tdm_api);
|
|
}
|
|
|
|
sangoma_wait_obj_delete(&sng_wait_object);
|
|
|
|
sangoma_close(&fd);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
\fn int open_sangoma_device()
|
|
\brief Open a single span chan device
|
|
\return 0 ok otherise error.
|
|
|
|
This function will open a single span chan.
|
|
|
|
However it can be rewritten to iterate for all spans and chans and try to
|
|
open all existing wanpipe devices.
|
|
|
|
For each opened device, a wait object will be initialized.
|
|
For each device, configure the chunk size for tx/rx
|
|
enable events such as DTMF/RBS ...etc
|
|
*/
|
|
int open_sangoma_device()
|
|
{
|
|
int span, chan, err = 0, open_dev_cnt = 0;
|
|
sangoma_status_t status;
|
|
sng_fd_t dev_fd = INVALID_HANDLE_VALUE;
|
|
wanpipe_api_t tdm_api;
|
|
|
|
span = wanpipe_port_no;
|
|
chan = wanpipe_if_no;
|
|
|
|
/* span and chan are 1-based */
|
|
dev_fd = sangoma_open_api_span_chan(span, chan);
|
|
if( dev_fd == INVALID_HANDLE_VALUE){
|
|
printf("Warning: Failed to open span %d, chan %d\n", span , chan);
|
|
return 1;
|
|
}else{
|
|
printf("Successfuly opened span %d, chan %d\n", span , chan);
|
|
}
|
|
|
|
memset(&tdm_api, 0x00, sizeof(tdm_api));
|
|
|
|
status = sangoma_wait_obj_create(&sangoma_wait_objects[open_dev_cnt], dev_fd, SANGOMA_DEVICE_WAIT_OBJ);
|
|
if(status != SANG_STATUS_SUCCESS){
|
|
printf("Error: Failed to create 'sangoma_wait_object'!\n");
|
|
return 1;
|
|
}
|
|
sangoma_channels[open_dev_cnt].channo = chan;
|
|
sangoma_channels[open_dev_cnt].spanno = span;
|
|
sangoma_wait_obj_set_context(sangoma_wait_objects[open_dev_cnt], &sangoma_channels[open_dev_cnt]);
|
|
/* open_dev_cnt++; */
|
|
|
|
if((err = sangoma_get_full_cfg(dev_fd, &tdm_api))){
|
|
return 1;
|
|
}
|
|
|
|
if(set_codec_slinear){
|
|
printf("Setting SLINEAR codec\n");
|
|
if((err=sangoma_tdm_set_codec(dev_fd, &tdm_api, WP_SLINEAR))){
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(set_codec_none){
|
|
printf("Disabling codec\n");
|
|
if((err=sangoma_tdm_set_codec(dev_fd, &tdm_api, WP_NONE))){
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(usr_period){
|
|
printf("Setting user period: %d\n", usr_period);
|
|
if((err=sangoma_tdm_set_usr_period(dev_fd, &tdm_api, usr_period))){
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(set_codec_slinear || usr_period || set_codec_none){
|
|
/* display new configuration AFTER it was changed */
|
|
if((err=sangoma_get_full_cfg(dev_fd, &tdm_api))){
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(dtmf_enable_octasic == 1){
|
|
poll_events_bitmap |= POLLPRI;
|
|
/* enable dtmf detection on Octasic chip */
|
|
if((err=sangoma_tdm_enable_dtmf_events(dev_fd, &tdm_api))){
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(dtmf_enable_remora == 1){
|
|
poll_events_bitmap |= POLLPRI;
|
|
/* enable dtmf detection on Sangoma's Remora SLIC chip (A200 ONLY) */
|
|
if((err=sangoma_tdm_enable_rm_dtmf_events(dev_fd, &tdm_api))){
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(remora_hook == 1){
|
|
poll_events_bitmap |= POLLPRI;
|
|
if((err=sangoma_tdm_enable_rxhook_events(dev_fd, &tdm_api))){
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(rbs_events == 1){
|
|
poll_events_bitmap |= POLLPRI;
|
|
if((err=sangoma_tdm_enable_rbs_events(dev_fd, &tdm_api, 20))){
|
|
return 1;
|
|
}
|
|
}
|
|
if (buffer_multiplier) {
|
|
printf("Setting buffer multiplier to %i\n",buffer_multiplier);
|
|
err=sangoma_tdm_set_buffer_multiplier(dev_fd,&tdm_api,buffer_multiplier);
|
|
if (err) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
printf("Device Config RxQ=%i TxQ=%i \n",
|
|
sangoma_get_rx_queue_sz(dev_fd,&tdm_api),
|
|
sangoma_get_rx_queue_sz(dev_fd,&tdm_api));
|
|
|
|
sangoma_set_rx_queue_sz(dev_fd,&tdm_api,20);
|
|
sangoma_set_tx_queue_sz(dev_fd,&tdm_api,30);
|
|
|
|
printf("Device Config RxQ=%i TxQ=%i \n",
|
|
sangoma_get_rx_queue_sz(dev_fd,&tdm_api),
|
|
sangoma_get_tx_queue_sz(dev_fd,&tdm_api));
|
|
|
|
sangoma_flush_bufs(dev_fd,&tdm_api);
|
|
|
|
sangoma_print_stats(dev_fd);
|
|
|
|
|
|
return err;
|
|
}
|
|
|
|
/*!
|
|
\fn int __cdecl main(int argc, char* argv[])
|
|
\brief Main function that starts the sample code
|
|
\param argc number of arguments
|
|
\param argv argument list
|
|
*/
|
|
int __cdecl main(int argc, char* argv[])
|
|
{
|
|
int proceed, i;
|
|
|
|
proceed=init_args(argc,argv);
|
|
if (proceed != WAN_TRUE){
|
|
usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
/* register Ctrl+C handler - we want a clean termination */
|
|
#if defined(__WINDOWS__)
|
|
if (!SetConsoleCtrlHandler(TerminateHandler, TRUE)) {
|
|
printf("ERROR : Unable to register terminate handler ( %d ).\nProcess terminated.\n",
|
|
GetLastError());
|
|
return -1;
|
|
}
|
|
#else
|
|
signal(SIGHUP,TerminateHandler);
|
|
signal(SIGTERM,TerminateHandler);
|
|
#endif
|
|
|
|
for(i = 0; i < TEST_NUMBER_OF_OBJECTS; i++){
|
|
sangoma_wait_objects[i] = NULL;
|
|
}
|
|
|
|
poll_events_bitmap = 0;
|
|
if(read_enable == 1){
|
|
poll_events_bitmap |= POLLIN;
|
|
}
|
|
|
|
if(write_enable == 1 && rx2tx == 1){
|
|
/* These two options are mutually exclusive because 'rx2tx' option
|
|
* indicates "use Reciever as the timing source for Transmitter". */
|
|
write_enable = 0;
|
|
}
|
|
|
|
if(write_enable == 1){
|
|
poll_events_bitmap |= POLLOUT;
|
|
}
|
|
|
|
/* Front End connect/disconnect, and other events, such as DTMF... */
|
|
poll_events_bitmap |= (POLLHUP | POLLPRI);
|
|
#if defined(__WINDOWS__)
|
|
printf("Enabling Poll Events:\n");
|
|
print_poll_event_bitmap(poll_events_bitmap);
|
|
#endif
|
|
printf("Connecting to Port/Span: %d, Interface/Chan: %d\n",
|
|
wanpipe_port_no, wanpipe_if_no);
|
|
|
|
|
|
if(open_sangoma_device()){
|
|
return -1;
|
|
}
|
|
|
|
printf("********************************\n");
|
|
printf("files_used: 0x%x\n", files_used);
|
|
printf("********************************\n");
|
|
if(files_used & RX_FILE_USED){
|
|
pRxFile = fopen( (const char*)&rx_file[0], "wb" );
|
|
if(pRxFile == NULL){
|
|
printf("Can't open Rx file: [%s]!!\n", rx_file);
|
|
}else{
|
|
printf("Open Rx file: %s. OK.\n", rx_file);
|
|
}
|
|
}
|
|
|
|
handle_span_chan(1 /* handle a single device */);
|
|
|
|
/* returned from main loop, do the cleanup before exiting: */
|
|
cleanup();
|
|
|
|
printf("\nSample application exiting.(press any key)\n");
|
|
_getch();
|
|
return 0;
|
|
}
|