1055 lines
31 KiB
Plaintext
1055 lines
31 KiB
Plaintext
//
|
|
// Copyright (c) 1984-2008 Sangoma Technologies Inc.
|
|
//
|
|
// Author : David Rokhvarg <davidr@sangoma.com>
|
|
//
|
|
// sample.cpp:
|
|
// Sample C++ program for the following Sangoma APIs:
|
|
// 1. HDLC Streaming API
|
|
// 2. Bit Streaming API
|
|
// 3. "TDM VOICE API"
|
|
//
|
|
//Note 1: the header files are in "include" directory,
|
|
// your compiler should know where to look for
|
|
// the Header files.
|
|
//
|
|
//
|
|
// Target: Windows XP/2003 and later. Win32 Console.
|
|
//
|
|
// For Version beta-6,0,6,2 and later of the API driver (sdladrv.sys)
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
//Device Names formed as follows:
|
|
// "\\\\.\\WANPIPE1_IF0" - corresponds to Group 1 on WANPIPE1
|
|
//
|
|
// "\\\\.\\WANPIPE1_IF1" - corresponds to Group 2 on WANPIPE1
|
|
//
|
|
// "\\\\.\\WANPIPE1_IF2" - corresponds to Group 3 on WANPIPE1
|
|
//
|
|
// "\\\\.\\WANPIPE2_IF0" - corresponds to Group 1 on WANPIPE2
|
|
//
|
|
// "\\\\.\\WANPIPE2_IF1" - corresponds to Group 2 on WANPIPE2
|
|
//
|
|
//and so on...
|
|
//
|
|
//(WANPIPE1 is Port 1 on the first installed card)
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
#define SET_DRV_CFG 0
|
|
|
|
#include "sangoma_port.h"
|
|
#include "sangoma_port_configurator.h"
|
|
#include "sangoma_interface.h"
|
|
|
|
#ifndef MAX_PATH
|
|
#define MAX_PATH 100
|
|
#endif
|
|
|
|
#if !defined(__WINDOWS__)
|
|
#define EnterCriticalSection(arg)
|
|
#define LeaveCriticalSection(arg)
|
|
#define InitializeCriticalSection(arg)
|
|
#endif
|
|
|
|
|
|
//globals:
|
|
uint16_t wanpipe_number = 1;
|
|
uint16_t interface_number = 1;
|
|
uint8_t silent = 0;
|
|
uint16_t txlength = 128;
|
|
uint8_t Rx_to_Tx_loopback = 0;
|
|
|
|
static char szTxFileName[MAX_PATH];
|
|
|
|
#if defined(__WINDOWS__)
|
|
//critical section for synchronizing access to 'stdout' between the threads
|
|
CRITICAL_SECTION PrintCriticalSection;
|
|
//critical section for TDM events
|
|
CRITICAL_SECTION TdmEventCriticalSection;
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
callback_functions_t callback_functions;
|
|
//prototypes of the callback functions:
|
|
static int got_rx_data(void *sang_if_ptr, void *rx_data);
|
|
static void got_TdmApiEvent(void *sang_if_ptr, void *event_data);
|
|
|
|
#if USE_STELEPHONY_API
|
|
//Sangoma Telephony API (Stelephony.dll) provides the following telephony services:
|
|
//1. FSK Caller ID detection for Analog FXO.
|
|
//2. Software DTMF detection.
|
|
static void FSKCallerIDEvent(void *callback_context, LPCTSTR Name, LPCTSTR CallerNumber, LPCTSTR CalledNumber, LPCTSTR DateTime);
|
|
static void DTMFEvent(void *callback_context, long Key);
|
|
static void Q931Event(void *callback_context, stelephony_q931_event *pQ931Event);
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
typedef struct{
|
|
void *sang_if_ptr;
|
|
wp_tdm_api_event_t event;
|
|
}TDM_API_EVENT_THREAD_PARAM;
|
|
|
|
#if defined (__WINDWOS__)
|
|
DWORD TdmApiEventThreadFunc(LPDWORD lpdwParam);
|
|
#else
|
|
void *TdmApiEventThreadFunc(void *lpdwParam);
|
|
#endif
|
|
//////////////////////////////////////////////////////////////////
|
|
#define DBG_MAIN if(1)printf
|
|
#define ERR_MAIN if(1)printf
|
|
#define INFO_MAIN if(1)printf
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
static int set_port_configration();
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
sangoma_interface* init(int wanpipe_number, int interface_number)
|
|
{
|
|
sangoma_interface *sang_if = NULL;
|
|
|
|
DBG_MAIN("init()\n");
|
|
|
|
callback_functions.got_rx_data = got_rx_data;
|
|
callback_functions.got_TdmApiEvent = got_TdmApiEvent;
|
|
#if USE_STELEPHONY_API
|
|
callback_functions.FSKCallerIDEvent = FSKCallerIDEvent;
|
|
callback_functions.DTMFEvent = DTMFEvent;
|
|
callback_functions.Q931Event = Q931Event;
|
|
#endif
|
|
|
|
sang_if = new sangoma_interface(wanpipe_number, interface_number);
|
|
if(sang_if->init(&callback_functions)){
|
|
delete sang_if;
|
|
return NULL;
|
|
}
|
|
|
|
DBG_MAIN("init(): OK\n");
|
|
return sang_if;
|
|
}
|
|
|
|
void cleanup(sangoma_interface *sang_if)
|
|
{
|
|
DBG_MAIN("cleanup()\n");
|
|
|
|
if(sang_if){
|
|
delete sang_if;
|
|
}
|
|
}
|
|
|
|
int start(sangoma_interface *sang_if)
|
|
{
|
|
DBG_MAIN("start()\n");
|
|
return sang_if->run();
|
|
}
|
|
|
|
void stop(sangoma_interface *sang_if)
|
|
{
|
|
DBG_MAIN("stop()\n");
|
|
sang_if->stop();
|
|
}
|
|
|
|
void PrintRxData(RX_DATA_STRUCT* pRx)
|
|
{
|
|
api_header_t* pri;
|
|
USHORT datlen;
|
|
PUCHAR data;
|
|
static unsigned int rx_counter = 0;
|
|
|
|
pri = &pRx->api_header;
|
|
|
|
//NOTE: if running in BitStream mode, there will be TOO MUCH to print
|
|
datlen = pri->data_length;
|
|
data = pRx->data;
|
|
|
|
rx_counter++;
|
|
if(silent){
|
|
if((rx_counter % 1000) == 0){
|
|
INFO_MAIN("Rx counter:%d, Rx datlen : %d. Data :\n", rx_counter, datlen);
|
|
}
|
|
return;
|
|
}else{
|
|
INFO_MAIN("Rx counter:%d, Rx datlen : %d. Data :\n", rx_counter, datlen);
|
|
}
|
|
|
|
#if 1
|
|
for(int ln = 0; ln < datlen; ln++){
|
|
if((ln % 20 == 0)){
|
|
if(ln){
|
|
INFO_MAIN("\n");
|
|
}
|
|
INFO_MAIN("%04d ", ln/20);
|
|
}
|
|
INFO_MAIN("%02X ", data[ln]);
|
|
}
|
|
INFO_MAIN("\n");
|
|
#endif
|
|
}
|
|
|
|
static int got_rx_data(void *sang_if_ptr, void *rx_data)
|
|
{
|
|
sangoma_interface *sang_if;
|
|
//Do something with data received from Sangoma interface.
|
|
//
|
|
//Fore example, transimit back everything what was received:
|
|
sang_if = (sangoma_interface*)sang_if_ptr;
|
|
|
|
if(Rx_to_Tx_loopback == 1){
|
|
sang_if->transmit((TX_RX_DATA_STRUCT*)rx_data);
|
|
}
|
|
|
|
EnterCriticalSection(&PrintCriticalSection);
|
|
PrintRxData((RX_DATA_STRUCT*)rx_data);
|
|
LeaveCriticalSection(&PrintCriticalSection);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void got_TdmApiEvent(void *sang_if_ptr, void *event_data)
|
|
{
|
|
TDM_API_EVENT_THREAD_PARAM *param =
|
|
(TDM_API_EVENT_THREAD_PARAM*)malloc(sizeof(TDM_API_EVENT_THREAD_PARAM));
|
|
|
|
if(param == NULL){
|
|
ERR_MAIN("Failed to allocate memory for 'Event Thread parameter'!!\n");
|
|
return;
|
|
}
|
|
|
|
memcpy(¶m->event, event_data, sizeof(wp_tdm_api_event_t));
|
|
param->sang_if_ptr = sang_if_ptr;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//Handling of Events must be done OUTSIDE of the REAL-TIME Rx thread//
|
|
//because it may make take a lot of time. //
|
|
//Create a special thread for Event hadling. //
|
|
//////////////////////////////////////////////////////////////////////
|
|
#if defined(__WINDOWS__)
|
|
DWORD dwThreadId;
|
|
|
|
if(CreateThread(
|
|
NULL, /* no security attributes */
|
|
0, /* use default stack size */
|
|
(LPTHREAD_START_ROUTINE)TdmApiEventThreadFunc, /* thread function */
|
|
param, /* argument to thread function */
|
|
0, /* use default creation flags */
|
|
&dwThreadId /* returns the thread identifier */
|
|
) == NULL){
|
|
ERR_MAIN("Failed to create 'TdmApiEvent' thread!!\n");
|
|
}
|
|
#else
|
|
//FIXME: implement the thread. Consider using sangoma_cthread class.
|
|
TdmApiEventThreadFunc(param);
|
|
#endif
|
|
}
|
|
|
|
#ifdef __WINDWOS__
|
|
DWORD TdmApiEventThreadFunc(LPDWORD lpdwParam)
|
|
#else
|
|
void *TdmApiEventThreadFunc(void *lpdwParam)
|
|
#endif
|
|
{
|
|
TDM_API_EVENT_THREAD_PARAM *param;
|
|
sangoma_interface *sang_if;
|
|
wp_tdm_api_event_t *wp_tdm_api_event;
|
|
|
|
EnterCriticalSection(&TdmEventCriticalSection);
|
|
|
|
param = (TDM_API_EVENT_THREAD_PARAM*)lpdwParam;
|
|
|
|
wp_tdm_api_event = ¶m->event;
|
|
sang_if = (sangoma_interface*)param->sang_if_ptr;
|
|
|
|
DBG_MAIN( "TdmApiEventThreadFunc:: ifname: %s\n", sang_if->device_name);
|
|
|
|
switch(wp_tdm_api_event->wp_tdm_api_event_type)
|
|
{
|
|
case WP_TDMAPI_EVENT_DTMF:/* DTMF detected by Hardware */
|
|
DBG_MAIN("DTMF Event: Channel: %d, Digit: %c (Port: %s, Type:%s)!\n",
|
|
wp_tdm_api_event->channel,
|
|
wp_tdm_api_event->wp_tdm_api_event_dtmf_digit,
|
|
(wp_tdm_api_event->wp_tdm_api_event_dtmf_port == WAN_EC_CHANNEL_PORT_ROUT)?"ROUT":"SOUT",
|
|
(wp_tdm_api_event->wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT)?"PRESENT":"STOP");
|
|
|
|
break;
|
|
|
|
case WP_TDMAPI_EVENT_RXHOOK:
|
|
DBG_MAIN("RXHOOK Event: Channel: %d, %s! (0x%X)\n",
|
|
wp_tdm_api_event->channel,
|
|
WAN_EVENT_RXHOOK_DECODE(wp_tdm_api_event->wp_tdm_api_event_hook_state),
|
|
wp_tdm_api_event->wp_tdm_api_event_hook_state);
|
|
break;
|
|
|
|
case WP_TDMAPI_EVENT_RING_DETECT:
|
|
DBG_MAIN("RING Event: %s! (0x%X)\n",
|
|
WAN_EVENT_RING_DECODE(wp_tdm_api_event->wp_tdm_api_event_ring_state),
|
|
wp_tdm_api_event->wp_tdm_api_event_ring_state);
|
|
break;
|
|
|
|
case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
|
|
DBG_MAIN("RING TRIP Event: %s! (0x%X)\n",
|
|
WAN_EVENT_RING_TRIP_DECODE(wp_tdm_api_event->wp_tdm_api_event_ring_state),
|
|
wp_tdm_api_event->wp_tdm_api_event_ring_state);
|
|
break;
|
|
|
|
case WP_TDMAPI_EVENT_RBS:
|
|
DBG_MAIN("RBS Event: Channel: %d, 0x%X!\n",
|
|
wp_tdm_api_event->channel,
|
|
wp_tdm_api_event->wp_tdm_api_event_rbs_bits);
|
|
DBG_MAIN( "RX RBS: A:%1d B:%1d C:%1d D:%1d\n",
|
|
(wp_tdm_api_event->wp_tdm_api_event_rbs_bits & WAN_RBS_SIG_A) ? 1 : 0,
|
|
(wp_tdm_api_event->wp_tdm_api_event_rbs_bits & WAN_RBS_SIG_B) ? 1 : 0,
|
|
(wp_tdm_api_event->wp_tdm_api_event_rbs_bits & WAN_RBS_SIG_C) ? 1 : 0,
|
|
(wp_tdm_api_event->wp_tdm_api_event_rbs_bits & WAN_RBS_SIG_D) ? 1 : 0);
|
|
break;
|
|
|
|
case WP_TDMAPI_EVENT_LINK_STATUS:
|
|
DBG_MAIN("Link Status Event: %s! (0x%X)\n",
|
|
WAN_EVENT_LINK_STATUS_DECODE(wp_tdm_api_event->wp_tdm_api_event_link_status),
|
|
wp_tdm_api_event->wp_tdm_api_event_link_status);
|
|
break;
|
|
|
|
case WP_TDMAPI_EVENT_ALARM:
|
|
//FIXME: Alarm is NOT Link State
|
|
DBG_MAIN("New Link State: %s! (0x%X)\n",
|
|
(wp_tdm_api_event->wp_tdm_api_event_alarm == 0?"Connected":"Disconnected"),
|
|
wp_tdm_api_event->wp_tdm_api_event_alarm);
|
|
break;
|
|
|
|
default:
|
|
ERR_MAIN("Unknown TDM API Event: %d\n", wp_tdm_api_event->wp_tdm_api_event_type);
|
|
break;
|
|
}
|
|
|
|
free(lpdwParam);
|
|
LeaveCriticalSection(&TdmEventCriticalSection);
|
|
//Done with the Event, exit the thread.
|
|
return 0;
|
|
}
|
|
|
|
int tx_file(sangoma_interface *sang_if)
|
|
{
|
|
FILE *pFile;
|
|
unsigned int tx_counter=0, bytes_read_from_file, total_bytes_read_from_file=0;
|
|
TX_DATA_STRUCT local_tx_data;
|
|
|
|
pFile = fopen( szTxFileName, "rb" );
|
|
if( pFile == NULL){
|
|
ERR_MAIN( "Can't open file: [%s]\n", szTxFileName );
|
|
return 1;
|
|
}
|
|
|
|
do
|
|
{
|
|
//read tx data from the file. if 'bytes_read_from_file != TX_LENGTH', end of file is reached
|
|
bytes_read_from_file = fread( local_tx_data.data, 1, txlength /* MTU size */, pFile );
|
|
total_bytes_read_from_file += bytes_read_from_file;
|
|
|
|
local_tx_data.api_header.data_length = txlength;//ALWAYS transmit MTU size over the bitstream
|
|
local_tx_data.api_header.operation_status = SANG_STATUS_TX_TIMEOUT;
|
|
|
|
sang_if->transmit(&local_tx_data);
|
|
|
|
tx_counter++;
|
|
|
|
//DBG_MAIN("tx_counter: %u\r",tx_counter);
|
|
|
|
}while(bytes_read_from_file == txlength);
|
|
|
|
INFO_MAIN("Finished transmitting file \"%s\" (tx_counter: %u, total_bytes_read_from_file: %d)\n",
|
|
szTxFileName, tx_counter, total_bytes_read_from_file);
|
|
fclose( pFile );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int get_user_number()
|
|
{
|
|
int result = 1;
|
|
int retry_counter = 0;
|
|
|
|
while(scanf("%d", &result) == 0){
|
|
fflush( stdin );
|
|
INFO_MAIN("\nError: Not a numerical input!!\n");
|
|
if(retry_counter++ > 10){
|
|
INFO_MAIN("giving up...\n");
|
|
result = 1;
|
|
break;
|
|
}
|
|
}//while()
|
|
|
|
INFO_MAIN("User input: %d\n", result);
|
|
return result;
|
|
}
|
|
|
|
static int parse_command_line_args(int argc, char* argv[])
|
|
{
|
|
int i;
|
|
#define USAGE_STR \
|
|
"\n\
|
|
Usage: sample [-c] [-i] [-silent]\n\
|
|
\n\
|
|
Options:\n\
|
|
\t-c number Wanpipe number: 1,2,3...\n\
|
|
\t-i number Interface number 0,1,2,3,....\n\
|
|
\t-silent Disable display of Rx data\n\
|
|
\t-rx2tx All received data transmitted on the SAME interface\n\
|
|
\n\
|
|
Example: sample -c 1 -i 0\n"
|
|
|
|
for(i = 0; i < argc; i++){
|
|
|
|
if(_stricmp(argv[i], "-silent") == 0){
|
|
INFO_MAIN("disabling Rx data display...\n");
|
|
silent = 1;
|
|
}else if(_stricmp(argv[i], "help") == 0 || _stricmp(argv[i], "?") == 0 || _stricmp(argv[i], "/?") == 0){
|
|
INFO_MAIN(USAGE_STR);
|
|
return 1;
|
|
}else if(_stricmp(argv[i], "-c") == 0){
|
|
if (i+1 > argc-1){
|
|
INFO_MAIN("No Wanpipe number was provided!\n");
|
|
return 1;
|
|
}
|
|
wanpipe_number = (uint16_t)atoi(argv[i+1]);
|
|
INFO_MAIN("Using wanpipe number %d\n", wanpipe_number);
|
|
}else if(_stricmp(argv[i], "-i") == 0){
|
|
if (i+1 > argc-1){
|
|
INFO_MAIN("No Interface number was provided!\n");
|
|
return 1;
|
|
}
|
|
interface_number = (uint16_t)atoi(argv[i+1]);
|
|
INFO_MAIN("Using interface number %d\n", interface_number);
|
|
if(interface_number < 1){
|
|
ERR_MAIN("Invalid interface number %d!!\n", interface_number);
|
|
return 1;
|
|
}
|
|
}else if(strcmp(argv[i], "-rx2tx") == 0){
|
|
INFO_MAIN("enabling Rx to Tx loopback...\n");
|
|
Rx_to_Tx_loopback = 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int __cdecl main(int argc, char* argv[])
|
|
{
|
|
int rc, user_selection;
|
|
sangoma_interface *sang_if = NULL;
|
|
TX_DATA_STRUCT local_tx_data;
|
|
UCHAR tx_test_byte = 0;
|
|
|
|
if(parse_command_line_args(argc, argv)){
|
|
return 1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//An OPTIONAL step of setting the port configuration to different values from
|
|
//what is set in "Device Manager"-->"Sangoma Hardware Abstraction Driver".
|
|
#if SET_DRV_CFG
|
|
//set port configration and exit
|
|
set_port_configration();
|
|
return 0;
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//initialize critical section objects
|
|
InitializeCriticalSection(&PrintCriticalSection);
|
|
InitializeCriticalSection(&TdmEventCriticalSection);
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//User may provide Wanpipe Number and Interface Number as a command line arguments:
|
|
INFO_MAIN("Using wanpipe_number: %d, interface_number: %d\n", wanpipe_number, interface_number);
|
|
|
|
sang_if = init(wanpipe_number, interface_number);
|
|
|
|
if(sang_if == NULL){
|
|
return 1;
|
|
}
|
|
|
|
rc = start(sang_if);
|
|
if(rc){
|
|
cleanup(sang_if);
|
|
return rc;
|
|
}
|
|
|
|
do{
|
|
EnterCriticalSection(&PrintCriticalSection);
|
|
INFO_MAIN("Press 'q' to quit the program.\n");
|
|
INFO_MAIN("Press 't' to transmit data.\n");
|
|
INFO_MAIN("Press 's' to get Operational Statistics.\n");
|
|
INFO_MAIN("Press 'f' to reset (flush) Operational Statistics.\n");
|
|
|
|
if(sang_if->get_adapter_type() == WAN_MEDIA_T1 || sang_if->get_adapter_type() == WAN_MEDIA_E1){
|
|
INFO_MAIN("Press 'a' to get T1/E1 alarms.\n");
|
|
//RBS (CAS) commands
|
|
INFO_MAIN("Press 'g' to get RBS bits.\n");
|
|
INFO_MAIN("Press 'r' to set RBS bits.\n");
|
|
}
|
|
INFO_MAIN("Press 'i' to set Tx idle data buffer (BitStream only).\n");
|
|
switch(sang_if->get_adapter_type())
|
|
{
|
|
case WAN_MEDIA_T1:
|
|
//those commands valid only for T1
|
|
INFO_MAIN("Press 'l' to send 'activate remote loop back' signal.\n");
|
|
INFO_MAIN("Press 'd' to send 'deactivate remote loop back' signal.\n");
|
|
break;
|
|
|
|
case WAN_MEDIA_FXOFXS:
|
|
switch(sang_if->get_sub_media())
|
|
{
|
|
case MOD_TYPE_FXS:
|
|
INFO_MAIN("Press 'e' to listen to test tones on a phone connected to the A200-FXS\n");
|
|
INFO_MAIN("Press 'c' to ring/stop ring phone connected to the A200-FXS\n");
|
|
INFO_MAIN("Press 'n' to enable/disable reception of ON/OFF Hook events on A200-FXS\n");
|
|
INFO_MAIN("Press 'm' to enable DTMF events (on SLIC chip) on A200-FXS\n");
|
|
INFO_MAIN("Press 'j' to enable/disable reception of Ring Trip events on A200-FXS\n");
|
|
break;
|
|
|
|
case MOD_TYPE_FXO:
|
|
INFO_MAIN("Press 'u' to enable/disable reception of Ring Detect events on A200-FXO\n");
|
|
INFO_MAIN("Press 'h' to transmit ON/OFF hook signals on A200-FXO\n");
|
|
INFO_MAIN("Press 'a' to get Line Status (Connected/Disconnected)\n");
|
|
break;
|
|
}
|
|
break;
|
|
case WAN_MEDIA_BRI:
|
|
INFO_MAIN("Press 'k' to Activate/Deactivate ISDN BRI line\n");
|
|
break;
|
|
}
|
|
INFO_MAIN("Press 'o' to enable DTMF events (on Octasic chip)\n");
|
|
LeaveCriticalSection(&PrintCriticalSection);
|
|
|
|
user_selection = tolower(_getch());
|
|
switch(user_selection)
|
|
{
|
|
case 'q':
|
|
break;
|
|
case 't':
|
|
int cnt;
|
|
for(cnt = 0; cnt < 1; cnt++){
|
|
local_tx_data.api_header.data_length = txlength;
|
|
local_tx_data.api_header.operation_status = SANG_STATUS_TX_TIMEOUT;
|
|
|
|
//set the actual data for transmission
|
|
memset(local_tx_data.data, tx_test_byte, txlength);
|
|
|
|
sang_if->transmit(&local_tx_data);
|
|
|
|
tx_test_byte++;
|
|
}
|
|
break;
|
|
case 's':
|
|
{
|
|
aft_net_device_stats_t stats;
|
|
sang_if->get_operational_stats(&stats);
|
|
}
|
|
break;
|
|
case 'f':
|
|
sang_if->flush_operational_stats();
|
|
break;
|
|
case 'v':
|
|
{
|
|
DRIVER_VERSION version;
|
|
//read API driver version
|
|
sang_if->get_api_driver_version(&version);
|
|
INFO_MAIN("\nAPI version\t: %d,%d,%d,%d\n",
|
|
version.major, version.minor, version.minor1, version.minor2);
|
|
|
|
unsigned char customer_id = 0;
|
|
sang_if->get_card_customer_id(&customer_id);
|
|
INFO_MAIN("\ncustomer_id\t: 0x%02X\n", customer_id);
|
|
}
|
|
break;
|
|
case 'a':
|
|
unsigned char cFeStatus;
|
|
|
|
switch(sang_if->get_adapter_type())
|
|
{
|
|
case WAN_MEDIA_T1:
|
|
case WAN_MEDIA_E1:
|
|
//read T1/E1/56k alarms
|
|
sang_if->get_te1_56k_stat();
|
|
break;
|
|
|
|
case WAN_MEDIA_FXOFXS:
|
|
switch(sang_if->get_sub_media())
|
|
{
|
|
case MOD_TYPE_FXO:
|
|
cFeStatus = 0;
|
|
sang_if->sangoma_tdm_get_front_end_status(&cFeStatus);
|
|
INFO_MAIN("cFeStatus: %s (%d)\n", FE_STATUS_DECODE(cFeStatus), cFeStatus);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 'l':
|
|
//Activate Line/Remote Loopback mode:
|
|
sang_if->set_lb_modes(WAN_TE1_LINELB_MODE, WAN_TE1_LB_ENABLE);
|
|
//Activate Diagnostic Digital Loopback mode:
|
|
//sang_if->set_lb_modes(WAN_TE1_DDLB_MODE, WAN_TE1_LB_ENABLE);
|
|
//sang_if->set_lb_modes(WAN_TE1_PAYLB_MODE, WAN_TE1_LB_ENABLE);
|
|
break;
|
|
case 'd':
|
|
//Deactivate Line/Remote Loopback mode:
|
|
sang_if->set_lb_modes(WAN_TE1_LINELB_MODE, WAN_TE1_LB_DISABLE);
|
|
//Deactivate Diagnostic Digital Loopback mode:
|
|
//sang_if->set_lb_modes(WAN_TE1_DDLB_MODE, WAN_TE1_LB_DISABLE);
|
|
//sang_if->set_lb_modes(WAN_TE1_PAYLB_MODE, WAN_TE1_LB_DISABLE);
|
|
break;
|
|
|
|
|
|
case 'g'://read RBS bits
|
|
{
|
|
rbs_management_t rbs_management_struct = {0,0};
|
|
|
|
sang_if->enable_rbs_monitoring();
|
|
|
|
INFO_MAIN("Type Channel number and press <Enter>:\n");
|
|
rbs_management_struct.channel = get_user_number();//channels (Time Slots). Valid values: 1 to 24.
|
|
if(rbs_management_struct.channel < 1 || rbs_management_struct.channel > 24){
|
|
INFO_MAIN("Invalid RBS Channel number!\n");
|
|
break;
|
|
}
|
|
sang_if->get_rbs(&rbs_management_struct);
|
|
}
|
|
break;
|
|
case 'r'://set RBS bits
|
|
{
|
|
static rbs_management_t rbs_management_struct = {0,0};
|
|
|
|
sang_if->enable_rbs_monitoring();
|
|
|
|
INFO_MAIN("Type Channel number and press <Enter>:\n");
|
|
rbs_management_struct.channel = get_user_number();//channels (Time Slots). Valid values: 1 to 24.
|
|
if(rbs_management_struct.channel < 1 || rbs_management_struct.channel > 24){
|
|
INFO_MAIN("Invalid RBS Channel number!\n");
|
|
break;
|
|
}
|
|
/* 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(rbs_management_struct.ABCD_bits == WAN_RBS_SIG_A){
|
|
rbs_management_struct.ABCD_bits = WAN_RBS_SIG_B;
|
|
}else{
|
|
rbs_management_struct.ABCD_bits = WAN_RBS_SIG_A;
|
|
}
|
|
sang_if->set_rbs(&rbs_management_struct);
|
|
}
|
|
break;
|
|
case 'i':
|
|
sang_if->set_idle_tx_data_buffer(0x00);
|
|
break;
|
|
case 'c':
|
|
user_retry_ring_e_d:
|
|
INFO_MAIN("Press 'e' to START ring, 'd' to STOP ring, 't' to Toggle\n");
|
|
INFO_MAIN("\n");
|
|
user_selection = tolower(_getch());
|
|
switch(user_selection)
|
|
{
|
|
case 'e':
|
|
INFO_MAIN("Starting Ring ...%c\n",user_selection);
|
|
sang_if->start_ringing_phone();//start
|
|
break;
|
|
case 'd':
|
|
INFO_MAIN("Stopping Ring ... %c\n",user_selection);
|
|
sang_if->stop_ringing_phone();//stop
|
|
break;
|
|
case 't':
|
|
{
|
|
int x;
|
|
for (x=0;x<500;x++) {
|
|
sang_if->start_ringing_phone();
|
|
sang_if->start_ringing_phone();
|
|
//sangoma_msleep(500);
|
|
sang_if->stop_ringing_phone();//stop
|
|
sang_if->stop_ringing_phone();//stop
|
|
//sangoma_msleep(500);
|
|
sang_if->start_busy_tone();
|
|
sangoma_msleep(50);
|
|
sang_if->stop_all_tones();
|
|
sangoma_msleep(50);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
goto user_retry_ring_e_d;
|
|
break;
|
|
}
|
|
break;
|
|
case 'e':
|
|
INFO_MAIN("Press 'e' to START a Tone, 'd' to STOP a Tone.\n");
|
|
INFO_MAIN("\n");
|
|
|
|
switch(tolower(_getch()))
|
|
{
|
|
case 'e':
|
|
INFO_MAIN("Press 'r' for Ring Tone, 'd' for Dial Tone, 'b' for Busy Tone, 'c' for Congestion Tone.\n");
|
|
INFO_MAIN("\n");
|
|
switch(tolower(_getch()))
|
|
{
|
|
case 'r':
|
|
sang_if->start_ring_tone();
|
|
break;
|
|
case 'd':
|
|
sang_if->start_dial_tone();
|
|
break;
|
|
case 'b':
|
|
sang_if->start_busy_tone();
|
|
break;
|
|
case 'c':
|
|
default:
|
|
sang_if->start_congestion_tone();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'd':
|
|
default:
|
|
sang_if->stop_all_tones();//stop all tones
|
|
}
|
|
break;
|
|
case 'n':
|
|
INFO_MAIN("Press 'e' to ENABLE Rx Hook Events, 'd' to DISABLE Rx Hook Events.\n");
|
|
INFO_MAIN("\n");
|
|
switch(tolower(_getch()))
|
|
{
|
|
case 'e':
|
|
sang_if->sangoma_tdm_enable_rxhook_events();
|
|
break;
|
|
case 'd':
|
|
default:
|
|
sang_if->sangoma_tdm_disable_rxhook_events();
|
|
}
|
|
break;
|
|
case 'm':
|
|
//Enable/Disable DTMF events on SLIC chip.
|
|
//On Analog (A200) card only.
|
|
INFO_MAIN("Press 'e' to ENABLE Remora DTMF Events, 'd' to DISABLE Remora DTMF Events.\n");
|
|
INFO_MAIN("\n");
|
|
switch(tolower(_getch()))
|
|
{
|
|
case 'e':
|
|
sang_if->sangoma_tdm_enable_rm_dtmf_events();
|
|
break;
|
|
case 'd':
|
|
default:
|
|
sang_if->sangoma_tdm_disable_rm_dtmf_events();
|
|
}
|
|
break;
|
|
case 'o':
|
|
{
|
|
//Enable DTMF events on Octasic chip.
|
|
//For both Analog (A200) and T1/E1 (A104D) cards, but only if the chip is present.
|
|
INFO_MAIN("Press 'e' to ENABLE Octasic DTMF Events, 'd' to DISABLE Octasic DTMF Events.\n");
|
|
uint8_t channel;
|
|
|
|
INFO_MAIN("\n");
|
|
switch(tolower(_getch()))
|
|
{
|
|
case 'e':
|
|
INFO_MAIN("Type Channel number and press <Enter>:\n");
|
|
channel = (uint8_t)get_user_number();//channels (Time Slots). Valid values: 1 to 31.
|
|
|
|
sang_if->sangoma_tdm_enable_dtmf_events(channel);
|
|
break;
|
|
case 'd':
|
|
default:
|
|
INFO_MAIN("Type Channel number and press <Enter>:\n");
|
|
channel = (uint8_t)get_user_number();//channels (Time Slots). Valid values: 1 to 31.
|
|
|
|
sang_if->sangoma_tdm_disable_dtmf_events(channel);
|
|
}
|
|
}
|
|
break;
|
|
case 'u':
|
|
//Enable/Disable Ring Detect events on FXO.
|
|
INFO_MAIN("Press 'e' to ENABLE Rx Ring Detect Events, 'd' to DISABLE Rx Ring Detect Events.\n");
|
|
INFO_MAIN("\n");
|
|
switch(tolower(_getch()))
|
|
{
|
|
case 'e':
|
|
sang_if->sangoma_tdm_enable_ring_detect_events();
|
|
break;
|
|
case 'd':
|
|
default:
|
|
sang_if->sangoma_tdm_disable_ring_detect_events();
|
|
}
|
|
break;
|
|
case 'j':
|
|
//Enable/Disable Ring Trip events on FXS.
|
|
INFO_MAIN("Press 'e' to ENABLE Rx Ring Trip Events, 'd' to DISABLE Rx Ring Trip Events.\n");
|
|
INFO_MAIN("\n");
|
|
switch(tolower(_getch()))
|
|
{
|
|
case 'e':
|
|
sang_if->sangoma_tdm_enable_ring_trip_detect_events();
|
|
break;
|
|
case 'd':
|
|
default:
|
|
sang_if->sangoma_tdm_disable_ring_trip_detect_events();
|
|
}
|
|
break;
|
|
case 'h':
|
|
INFO_MAIN("Press 'e' to transmit OFF hook signal, 'd' to transmit ON hook signal.\n");
|
|
INFO_MAIN("\n");
|
|
switch(tolower(_getch()))
|
|
{
|
|
case 'e':
|
|
sang_if->fxo_go_off_hook();
|
|
break;
|
|
case 'd':
|
|
default:
|
|
sang_if->fxo_go_on_hook();
|
|
}
|
|
break;
|
|
case 'k':
|
|
INFO_MAIN("Press 'e' to Activate, 'd' to De-Activate line.\n");
|
|
INFO_MAIN("\n");
|
|
switch(tolower(_getch()))
|
|
{
|
|
case 'e':
|
|
sang_if->sangoma_tdm_front_end_activate();
|
|
break;
|
|
case 'd':
|
|
default:
|
|
sang_if->sangoma_tdm_front_end_deactivate();
|
|
}
|
|
break;
|
|
default:
|
|
INFO_MAIN("Invalid command.\n");
|
|
}
|
|
|
|
}while(user_selection != 'q');
|
|
|
|
stop(sang_if);
|
|
cleanup(sang_if);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if SET_DRV_CFG
|
|
static int set_port_configration()
|
|
{
|
|
int rc = 0, is_te1_card = 0, user_selection;
|
|
hardware_info_t hardware_info;
|
|
port_cfg_t port_cfg;
|
|
|
|
sangoma_port_configurator *sng_port_cfg_obj;
|
|
|
|
sng_port_cfg_obj = new sangoma_port_configurator();
|
|
if(sng_port_cfg_obj == NULL || sng_port_cfg_obj->init(wanpipe_number)){
|
|
return 2;
|
|
}
|
|
|
|
rc = sng_port_cfg_obj->get_hardware_info(&hardware_info);
|
|
if(rc == SANG_STATUS_SUCCESS){
|
|
|
|
INFO_MAIN("card_model : %s (0x%08X)\n",
|
|
SDLA_ADPTR_NAME(hardware_info.card_model), hardware_info.card_model);
|
|
INFO_MAIN("firmware_version\t: 0x%02X\n", hardware_info.firmware_version);
|
|
INFO_MAIN("pci_bus_number\t\t: %d\n", hardware_info.pci_bus_number);
|
|
INFO_MAIN("pci_slot_number\t\t: %d\n", hardware_info.pci_slot_number);
|
|
INFO_MAIN("max_hw_ec_chans\t\t: %d\n", hardware_info.max_hw_ec_chans);
|
|
INFO_MAIN("port_number\t\t: %d\n", hardware_info.port_number);
|
|
|
|
}else{
|
|
delete sng_port_cfg_obj;
|
|
return 3;
|
|
}
|
|
|
|
|
|
#if defined(__WINDWOWS__)
|
|
rc = sng_port_cfg_obj->open_port_registry_key(&hardware_info);
|
|
if(rc != SANG_STATUS_SUCCESS){
|
|
delete sng_port_cfg_obj;
|
|
return 3;
|
|
}
|
|
#endif
|
|
|
|
memset(&port_cfg, 0x00, sizeof(port_cfg_t));
|
|
//get current configuration
|
|
rc = sng_port_cfg_obj->get_configration(&port_cfg);
|
|
if(rc != SANG_STATUS_SUCCESS){
|
|
delete sng_port_cfg_obj;
|
|
printf("Error: Failed to obtain configuration!\n");
|
|
return 3;
|
|
}
|
|
|
|
port_cfg.num_of_ifs=1;
|
|
port_cfg.if_cfg[0].magic = ROUTER_MAGIC;
|
|
#if 0
|
|
sprintf(port_cfg.if_cfg[0].usedby,"TDM_VOICE_API");
|
|
#else
|
|
sprintf(port_cfg.if_cfg[0].usedby,"TDM_VOICE_DCHAN");
|
|
#endif
|
|
port_cfg.if_cfg[0].active_ch=0x00FFFFFF;
|
|
port_cfg.if_cfg[0].hdlc_streaming=1;
|
|
sprintf(port_cfg.if_cfg[0].name, "w%dg1",wanpipe_number);
|
|
|
|
sng_port_cfg_obj->print_port_cfg_structure(&port_cfg);
|
|
|
|
switch(hardware_info.card_model)
|
|
{
|
|
case A101_ADPTR_1TE1:
|
|
case A101_ADPTR_2TE1:
|
|
case A104_ADPTR_4TE1:
|
|
case A108_ADPTR_8TE1:
|
|
is_te1_card = 1;
|
|
break;
|
|
}
|
|
|
|
|
|
if(is_te1_card){
|
|
wandev_conf_t *wandev_conf = &port_cfg.wandev_conf;
|
|
sdla_fe_cfg_t *sdla_fe_cfg = &wandev_conf->fe_cfg;
|
|
|
|
INFO_MAIN("\n");
|
|
INFO_MAIN("Press 't' to set T1 configration.\n");
|
|
INFO_MAIN("Press 'e' to set E1 configration.\n");
|
|
|
|
try_again:
|
|
user_selection = tolower(_getch());
|
|
|
|
switch(user_selection)
|
|
{
|
|
case 't'://T1
|
|
|
|
FE_MEDIA(sdla_fe_cfg) = WAN_MEDIA_T1;
|
|
FE_LCODE(sdla_fe_cfg) = WAN_LCODE_B8ZS;
|
|
FE_FRAME(sdla_fe_cfg) = WAN_FR_ESF;
|
|
|
|
FE_CLK(sdla_fe_cfg) = WAN_MASTER_CLK;//WAN_NORMAL_CLK;
|
|
//FE_REFCLK(sdla_fe_cfg) = 0; //optional
|
|
FE_HIMPEDANCE_MODE(sdla_fe_cfg) = WANOPT_NO;
|
|
|
|
FE_SIG_MODE(sdla_fe_cfg) = WAN_TE1_SIG_CCS;
|
|
FE_LBO(sdla_fe_cfg) = WAN_T1_LBO_0_DB;
|
|
|
|
FE_TDMV_LAW(sdla_fe_cfg) = WAN_TDMV_MULAW;
|
|
break;
|
|
case 'e'://E1
|
|
|
|
FE_MEDIA(sdla_fe_cfg) = WAN_MEDIA_E1;
|
|
FE_LCODE(sdla_fe_cfg) = WAN_LCODE_HDB3;
|
|
FE_FRAME(sdla_fe_cfg) = WAN_FR_CRC4;
|
|
|
|
FE_CLK(sdla_fe_cfg) = WAN_NORMAL_CLK;
|
|
//FE_REFCLK(sdla_fe_cfg) = 0;//optional
|
|
FE_HIMPEDANCE_MODE(sdla_fe_cfg) = WANOPT_NO;
|
|
|
|
FE_SIG_MODE(sdla_fe_cfg) = WAN_TE1_SIG_CCS;
|
|
FE_LBO(sdla_fe_cfg) = WAN_E1_120;
|
|
|
|
FE_TDMV_LAW(sdla_fe_cfg) = WAN_TDMV_ALAW;
|
|
break;
|
|
default:
|
|
INFO_MAIN("Invalid command %c.\n",user_selection);
|
|
goto try_again;
|
|
break;
|
|
}//switch(user_selection)
|
|
|
|
if(user_selection == 't' || user_selection == 'e'){
|
|
//as an EXAMPLE, set the default configration for T1 or E1:
|
|
rc = sng_port_cfg_obj->set_default_configuration(&port_cfg);
|
|
}
|
|
|
|
}//if(is_te1_card)
|
|
|
|
if(sng_port_cfg_obj != NULL){
|
|
delete sng_port_cfg_obj;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
#endif // SET_DRV_CFG
|
|
|
|
#if USE_STELEPHONY_API
|
|
static void FSKCallerIDEvent(void *callback_context,
|
|
LPCTSTR Name, LPCTSTR CallerNumber,
|
|
LPCTSTR CalledNumber, LPCTSTR DateTime)
|
|
{
|
|
//The "sangoma_interface" object was registered as the callback context in StelSetup() call.
|
|
sangoma_interface *sang_if = (sangoma_interface*)callback_context;
|
|
|
|
INFO_MAIN("\n%s: %s() - Start\n", sang_if->device_name, __FUNCTION__);
|
|
|
|
if(Name){
|
|
INFO_MAIN("Name: %S\n", Name);
|
|
}
|
|
if(CallerNumber){
|
|
INFO_MAIN("CallerNumber: %S\n", CallerNumber);
|
|
}
|
|
if(CalledNumber){
|
|
INFO_MAIN("CalledNumber: %S\n", CalledNumber);
|
|
}
|
|
if(DateTime){
|
|
INFO_MAIN("DateTime: %S\n", DateTime);
|
|
}
|
|
|
|
INFO_MAIN("%s() - End\n\n", __FUNCTION__);
|
|
}
|
|
|
|
static void DTMFEvent(void *callback_context, long Key)
|
|
{
|
|
//The "sangoma_interface" object was registered as the callback context in StelSetup() call.
|
|
sangoma_interface *sang_if = (sangoma_interface*)callback_context;
|
|
|
|
INFO_MAIN("\n%s: %s() - Start\n", sang_if->device_name, __FUNCTION__);
|
|
|
|
INFO_MAIN("Key: %c\n", Key);
|
|
|
|
INFO_MAIN("%s() - End\n\n", __FUNCTION__);
|
|
}
|
|
|
|
static void Q931Event(void *callback_context, stelephony_q931_event *pQ931Event)
|
|
{
|
|
//The "sangoma_interface" object was registered as the callback context in StelSetup() call.
|
|
sangoma_interface *sang_if = (sangoma_interface*)callback_context;
|
|
|
|
//INFO_MAIN("\n%s: %s() - Start\n", sang_if->device_name, __FUNCTION__);
|
|
#if 0
|
|
INFO_MAIN("\nFound %d bytes of data: ", pQ931Event->dataLength);
|
|
for (int i=0; i < pQ931Event->dataLength;i++){
|
|
INFO_MAIN("%02X ",pQ931Event->data[i]);
|
|
}
|
|
INFO_MAIN("\n");
|
|
#endif
|
|
|
|
INFO_MAIN("Message Received on: %02d/%02d/%02d @ %02d:%02d:%02d.%02d\n",pQ931Event->tv.wMonth,pQ931Event->tv.wDay,pQ931Event->tv.wYear,
|
|
pQ931Event->tv.wHour,pQ931Event->tv.wMinute,pQ931Event->tv.wSecond,pQ931Event->tv.wMilliseconds);
|
|
|
|
INFO_MAIN("Message Type is: %s\n",pQ931Event->msg_type);
|
|
INFO_MAIN("Length of Call Reference Field is: %d\n", pQ931Event->len_callRef);
|
|
INFO_MAIN("Message Call Reference is : 0X%s\n",pQ931Event->callRef);
|
|
|
|
if (pQ931Event->cause_code > 0){
|
|
INFO_MAIN("Cause code found = %d \n", pQ931Event->cause_code);
|
|
}
|
|
|
|
if (pQ931Event->chan > 0){
|
|
INFO_MAIN("B-channel used = %d \n", pQ931Event->chan);
|
|
}
|
|
|
|
if (pQ931Event->calling_num_digits_count > 0 ){
|
|
INFO_MAIN("Found %d digits for calling number \n", pQ931Event->calling_num_digits_count);
|
|
INFO_MAIN("Presentation indicator is = %d \n",pQ931Event->calling_num_presentation);
|
|
INFO_MAIN("Screening indicator is = %d \n",pQ931Event->calling_num_screening_ind);
|
|
INFO_MAIN("Calling number is = %s\n",pQ931Event->calling_num_digits);
|
|
}
|
|
|
|
if (pQ931Event->called_num_digits_count > 0 ){
|
|
INFO_MAIN("Found %d digits for called number \n", pQ931Event->called_num_digits_count);
|
|
INFO_MAIN("Called number is = %s\n",pQ931Event->called_num_digits);
|
|
}
|
|
|
|
if (pQ931Event->rdnis_digits_count > 0 ){
|
|
INFO_MAIN("Found %d digits for RDNIS\n", pQ931Event->rdnis_digits_count);
|
|
INFO_MAIN("RDNIS is = %s\n",pQ931Event->rdnis_string);
|
|
}
|
|
//INFO_MAIN("%s() - End\n\n", __FUNCTION__);
|
|
}
|
|
|
|
#endif
|