1754 lines
44 KiB
Plaintext
1754 lines
44 KiB
Plaintext
/*******************************************************************************//**
|
|
* \file libsangoma.c
|
|
* \brief Wanpipe API Code Library for Sangoma AFT T1/E1/Analog/BRI/Serial hardware
|
|
*
|
|
* Author(s): Nenad Corbic <ncorbic@sangoma.com>
|
|
* David Rokhvarg <davidr@sangoma.com>
|
|
* Michael Jerris <mike@jerris.com>
|
|
* Anthony Minessale II <anthmct@yahoo.com>
|
|
*
|
|
* Copyright: (c) 2005-2008 Nenad Corbic <ncorbic@sangoma.com>
|
|
*
|
|
* * 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"
|
|
|
|
/*!
|
|
\def DFT_CARD
|
|
\brief Default card name. Deprecated not used
|
|
*/
|
|
#define DFT_CARD "wanpipe1"
|
|
|
|
|
|
#ifndef WP_API_FEATURE_FE_ALARM
|
|
#warning "Warning: SANGOMA API FE ALARM not supported by driver"
|
|
#endif
|
|
|
|
#ifndef WP_API_FEATURE_DTMF_EVENTS
|
|
#warning "Warning: SANGOMA API DTMF not supported by driver"
|
|
#endif
|
|
|
|
#ifndef WP_API_FEATURE_EVENTS
|
|
#warning "Warning: SANGOMA API EVENTS not supported by driver"
|
|
#endif
|
|
|
|
#ifndef WP_API_FEATURE_LINK_STATUS
|
|
#warning "Warning: SANGOMA API LINK STATUS not supported by driver"
|
|
#endif
|
|
|
|
/*!
|
|
\def DEV_NAME_LEN
|
|
\brief String length of device name
|
|
*/
|
|
#define DEV_NAME_LEN 100
|
|
|
|
|
|
static void libsng_dbg(const char * fmt, ...)
|
|
{
|
|
va_list args;
|
|
char buf[1024];
|
|
va_start(args, fmt);
|
|
_vsnprintf(buf, sizeof(buf), fmt, args);
|
|
#if defined(WIN32)
|
|
OutputDebugString(buf);
|
|
#else
|
|
printf(buf);
|
|
#endif
|
|
va_end(args);
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
* WINDOWS Only Section
|
|
*************************************************************************/
|
|
|
|
#define DBG_POLL if(0)libsng_dbg
|
|
#define DBG_POLL1 if(0)libsng_dbg
|
|
#define DBG_EVNT if(0)libsng_dbg
|
|
#define DBG_ERR if(0)libsng_dbg
|
|
#define DBG_INIT if(0)libsng_dbg
|
|
|
|
#if defined(WIN32)
|
|
|
|
/*
|
|
\fn static void DecodeLastError(LPSTR lpszFunction)
|
|
\brief Decodes the Error in radable format.
|
|
\param lpszFunction error string
|
|
|
|
Private Windows Only Function
|
|
*/
|
|
static void DecodeLastError(LPSTR lpszFunction)
|
|
{
|
|
LPVOID lpMsgBuf;
|
|
DWORD dwLastErr = GetLastError();
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
dwLastErr,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
|
(LPTSTR) &lpMsgBuf,
|
|
0,
|
|
NULL
|
|
);
|
|
// Display the string.
|
|
DBG_POLL("Last Error in %s(): %s (%d)\n", lpszFunction, lpMsgBuf, dwLastErr);
|
|
// Free the buffer.
|
|
LocalFree( lpMsgBuf );
|
|
}
|
|
|
|
/*
|
|
\fn static int handle_device_ioctl_result(int bResult)
|
|
\brief Checks result code of ioctl
|
|
\param bResult result of ioctl call
|
|
|
|
Private Windows Only Function
|
|
*/
|
|
static u16 handle_device_ioctl_result(int bResult, char *caller_name)
|
|
{
|
|
if(bResult == 0){
|
|
//error
|
|
DecodeLastError(caller_name);
|
|
return 1;
|
|
|
|
}else{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
\fn static int DoManagementCommand(HANDLE fd, wan_udp_hdr_t* wan_udp)
|
|
\brief Executes Driver Management Command
|
|
\param fd device file descriptor
|
|
\param wan_udp managemet cmd structure
|
|
|
|
Private Windows Function
|
|
*/
|
|
static int DoManagementCommand(HANDLE fd, wan_udp_hdr_t* wan_udp)
|
|
{
|
|
DWORD ln, bIoResult;
|
|
unsigned char id = 0;
|
|
|
|
wan_udp->wan_udphdr_request_reply = 0x01;
|
|
wan_udp->wan_udphdr_id = id;
|
|
wan_udp->wan_udphdr_return_code = WAN_UDP_TIMEOUT_CMD;
|
|
|
|
bIoResult = DeviceIoControl(
|
|
fd,
|
|
IoctlManagementCommand,
|
|
(LPVOID)wan_udp,
|
|
sizeof(wan_udp_hdr_t),
|
|
(LPVOID)wan_udp,
|
|
sizeof(wan_udp_hdr_t),
|
|
(LPDWORD)(&ln),
|
|
(LPOVERLAPPED)NULL
|
|
);
|
|
|
|
return handle_device_ioctl_result(bIoResult, __FUNCTION__);
|
|
}
|
|
|
|
/*
|
|
\fn static int DoTdmvApiCommand(HANDLE fd, wanpipe_tdm_api_cmd_t *api_cmd)
|
|
\brief Executes Driver TDM API Command
|
|
\param fd device file descriptor
|
|
\param api_cmd tdm_api managemet cmd structure
|
|
|
|
Private Windows Function
|
|
*/
|
|
static int DoTdmvApiCommand(HANDLE fd, wanpipe_tdm_api_cmd_t *api_cmd)
|
|
{
|
|
DWORD ln, bIoResult;
|
|
|
|
bIoResult = DeviceIoControl(
|
|
fd,
|
|
IoctlTdmApiCommand,
|
|
(LPVOID)api_cmd,
|
|
sizeof(wanpipe_tdm_api_cmd_t),
|
|
(LPVOID)api_cmd,
|
|
sizeof(wanpipe_tdm_api_cmd_t),
|
|
(LPDWORD)(&ln),
|
|
(LPOVERLAPPED)NULL
|
|
);
|
|
|
|
return handle_device_ioctl_result(bIoResult, __FUNCTION__);
|
|
}
|
|
|
|
/*
|
|
\fn static int tdmv_api_ioctl(HANDLE fd, wanpipe_tdm_api_cmd_t *api_cmd)
|
|
\brief Executes Driver TDM API Command Wrapper Function
|
|
\param fd device file descriptor
|
|
\param api_cmd tdm_api managemet cmd structure
|
|
|
|
Private Windows Function
|
|
*/
|
|
static int tdmv_api_ioctl(HANDLE fd, wanpipe_tdm_api_cmd_t *api_cmd)
|
|
{
|
|
if(DoTdmvApiCommand(fd, api_cmd)){
|
|
return SANG_STATUS_GENERAL_ERROR;
|
|
}
|
|
|
|
return api_cmd->result;
|
|
}
|
|
|
|
/*
|
|
\fn static USHORT DoReadCommand(HANDLE drv, RX_DATA_STRUCT * pRx)
|
|
\brief API READ Function
|
|
\param drv device file descriptor
|
|
\param pRx receive data structure
|
|
|
|
Private Windows Function
|
|
In Legacy API mode this fuction will Block if there is no data.
|
|
In API mode no function is allowed to Block
|
|
*/
|
|
static USHORT DoReadCommand(HANDLE drv, RX_DATA_STRUCT * pRx)
|
|
{
|
|
DWORD ln, bIoResult;
|
|
|
|
bIoResult = DeviceIoControl(
|
|
drv,
|
|
IoctlReadCommand,
|
|
(LPVOID)NULL,//NO input buffer!
|
|
0,
|
|
(LPVOID)pRx,
|
|
sizeof(RX_DATA_STRUCT),
|
|
(LPDWORD)(&ln),
|
|
(LPOVERLAPPED)NULL);
|
|
|
|
return handle_device_ioctl_result(bIoResult, __FUNCTION__);
|
|
}
|
|
|
|
/*
|
|
\fn static UCHAR DoWriteCommand(HANDLE drv, TX_DATA_STRUCT * pTx)
|
|
\brief API Write Function
|
|
\param drv device file descriptor
|
|
\param pRx receive data structure
|
|
|
|
Private Windows Function
|
|
In Legacy API mode this fuction will Block if data is busy.
|
|
In API mode no function is allowed to Block
|
|
*/
|
|
static UCHAR DoWriteCommand(HANDLE drv,
|
|
void *input_data_buffer, u32 size_of_input_data_buffer,
|
|
void *output_data_buffer, u32 size_of_output_data_buffer
|
|
)
|
|
{
|
|
DWORD BytesReturned, bIoResult;
|
|
|
|
bIoResult = DeviceIoControl(
|
|
drv,
|
|
IoctlWriteCommand,
|
|
(LPVOID)input_data_buffer,
|
|
size_of_input_data_buffer,
|
|
(LPVOID)output_data_buffer,
|
|
size_of_output_data_buffer,
|
|
(LPDWORD)(&BytesReturned),
|
|
(LPOVERLAPPED)NULL);
|
|
|
|
return (UCHAR)handle_device_ioctl_result(bIoResult, __FUNCTION__);
|
|
}
|
|
|
|
/*
|
|
\fn static USHORT DoApiPollCommand(HANDLE drv, API_POLL_STRUCT *api_poll_ptr)
|
|
\brief Non Blocking API Poll function used to find out if Rx Data, Events or
|
|
Free Tx buffer available
|
|
\param drv device file descriptor
|
|
\param api_poll_ptr poll device that stores polling information read/write/event
|
|
\param overlapped pointer to system overlapped io structure.
|
|
|
|
Private Windows Function
|
|
This function blocks and waits for events: read/write/event/timeout
|
|
*/
|
|
static USHORT DoApiPollCommand(HANDLE drv, API_POLL_STRUCT *api_poll_ptr)
|
|
{
|
|
DWORD ln, bIoResult;
|
|
|
|
bIoResult = DeviceIoControl(
|
|
drv,
|
|
IoctlApiPoll,
|
|
(LPVOID)NULL,
|
|
0L,
|
|
(LPVOID)api_poll_ptr,
|
|
sizeof(API_POLL_STRUCT),
|
|
(LPDWORD)(&ln),
|
|
(LPOVERLAPPED)NULL);
|
|
|
|
return handle_device_ioctl_result(bIoResult, __FUNCTION__);
|
|
}
|
|
|
|
static int _SAPI_CALL sangoma_socket_poll(sangoma_wait_obj_t *sng_wait_obj)
|
|
{
|
|
API_POLL_STRUCT *api_poll = &sng_wait_obj->api_poll;
|
|
#if 0
|
|
DBG_POLL("%s(): span: %d, chan: %d\n", __FUNCTION__, sng_wait_obj->span, sng_wait_obj->chan);
|
|
#endif
|
|
memset(api_poll, 0x00, sizeof(API_POLL_STRUCT));
|
|
|
|
api_poll->user_flags_bitmap = sng_wait_obj->flags_in;
|
|
|
|
/* This call will return immediatly because it is "overlapped"!
|
|
* Caller of this function must implement the actual wait. */
|
|
if(DoApiPollCommand(sng_wait_obj->fd, api_poll)){
|
|
//failed
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static USHORT DoSetSharedEventCommand(HANDLE drv, PREGISTER_EVENT event)
|
|
{
|
|
DWORD ln, bIoResult;
|
|
|
|
bIoResult = DeviceIoControl(
|
|
drv,
|
|
IoctlSetSharedEvent,
|
|
(LPVOID)event,
|
|
sizeof(REGISTER_EVENT),
|
|
(LPVOID)event,
|
|
sizeof(REGISTER_EVENT),
|
|
(LPDWORD)(&ln),
|
|
(LPOVERLAPPED)NULL);
|
|
|
|
return handle_device_ioctl_result(bIoResult, __FUNCTION__);
|
|
}
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
|
/*********************************************************************//**
|
|
* Common Linux & Windows Code
|
|
*************************************************************************/
|
|
|
|
|
|
/*!
|
|
\fn void sangoma_close(sng_fd_t *fd)
|
|
\brief Close device file descriptor
|
|
\param fd device file descriptor
|
|
\return void
|
|
*/
|
|
void _SAPI_CALL sangoma_close(sng_fd_t *fd)
|
|
{
|
|
#if defined(WIN32)
|
|
if( *fd != INVALID_HANDLE_VALUE){
|
|
CloseHandle(*fd);
|
|
*fd = INVALID_HANDLE_VALUE;
|
|
}
|
|
#else
|
|
if (*fd >= 0) {
|
|
close(*fd);
|
|
*fd = -1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
\fn void sangoma_init_wait_obj(sangoma_wait_obj_t *sng_wait_obj, sng_fd_t fd, int span, int chan, int timeout, int flags_in, int object_type)
|
|
\brief Initialize a wait object that will be used in sangoma_socket_waitfor_many() function
|
|
\param sng_wait_obj pointer a single device object
|
|
\param fd device file descriptor
|
|
\param span span number starting from 1 to 255
|
|
\param chan chan number starting from 1 to 32
|
|
\param flags_in events to wait for (read/write/event)
|
|
\param object_type defines whether file descriptor is a sangoma device or other sytem file descriptor.
|
|
\return 0: success, non-zero: error
|
|
*/
|
|
int _SAPI_CALL sangoma_init_wait_obj(sangoma_wait_obj_t *sng_wait_obj, sng_fd_t fd, int span, int chan, int flags_in, int object_type)
|
|
{
|
|
int err = 0;
|
|
|
|
sng_wait_obj->fd = fd;
|
|
sng_wait_obj->flags_in = flags_in;
|
|
sng_wait_obj->span = span;
|
|
sng_wait_obj->chan = chan;
|
|
sng_wait_obj->object_type = object_type;
|
|
|
|
#if defined(WIN32)
|
|
DBG_INIT("%s(): fd:0x%X, span:%d, chan:%d, flags_in:0x%X, object_type:%s",
|
|
__FUNCTION__, fd, span, chan, flags_in, (object_type==SANGOMA_WAIT_OBJ?"SANGOMA_WAIT_OBJ":"UNKNOWN_WAIT_OBJ"));
|
|
|
|
memset(&sng_wait_obj->SharedEvent, 0x00, sizeof(sng_wait_obj->SharedEvent));
|
|
sng_wait_obj->SharedEvent.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
|
|
if(NULL == sng_wait_obj->SharedEvent.hEvent){
|
|
return 1;
|
|
}
|
|
|
|
if(SANGOMA_WAIT_OBJ == object_type){
|
|
err = DoSetSharedEventCommand(fd, &sng_wait_obj->SharedEvent);
|
|
}
|
|
|
|
DBG_INIT("%s(): returning: %d", __FUNCTION__, err);
|
|
#endif
|
|
|
|
return err;
|
|
}
|
|
|
|
/*!
|
|
\fn void sangoma_release_wait_obj(sangoma_wait_obj_t *sng_wait_obj)
|
|
\brief De-allocate all resources in a wait object
|
|
\param sng_wait_obj pointer a single device object
|
|
\return void
|
|
*/
|
|
void _SAPI_CALL sangoma_release_wait_obj(sangoma_wait_obj_t *sng_wait_obj)
|
|
{
|
|
if(sng_wait_obj->fd != INVALID_HANDLE_VALUE){
|
|
sangoma_close(&sng_wait_obj->fd);
|
|
sng_wait_obj->fd = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
sng_wait_obj->object_type = UNKNOWN_WAIT_OBJ;
|
|
}
|
|
|
|
/*!
|
|
\fn void sangoma_signal_wait_obj(sangoma_wait_obj_t *sng_wait_obj)
|
|
\brief Set wait object to a signalled state
|
|
\param sng_wait_obj pointer a single device object
|
|
\return void
|
|
*/
|
|
void _SAPI_CALL sangoma_signal_wait_obj(sangoma_wait_obj_t *sng_wait_obj)
|
|
{
|
|
#if defined(WIN32)
|
|
if(sng_wait_obj->SharedEvent.hEvent){
|
|
SetEvent(sng_wait_obj->SharedEvent.hEvent);
|
|
}
|
|
#else
|
|
//FIXME: implement signalling of the sng_wait_obj->fd ??
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
\fn int sangoma_socket_waitfor_many(sangoma_wait_obj_t sangoma_wait_objects[], int number_of_sangoma_wait_objects, uint32_t system_wait_timeout)
|
|
\brief Wait for multiple file descriptors - poll()
|
|
\param sangoma_wait_objects pointer to array of file descriptors to wait for
|
|
\param number_of_sangoma_wait_objects size of the array of file descriptors
|
|
\param system_wait_timeout timeout in miliseconds in case of no event
|
|
\return negative: error, 0: timeout, positive: event occured check in sangoma_wait_objects
|
|
*/
|
|
int _SAPI_CALL sangoma_socket_waitfor_many(sangoma_wait_obj_t sangoma_wait_objects[], int number_of_sangoma_wait_objects, uint32_t system_wait_timeout)
|
|
{
|
|
int i;
|
|
#if defined(WIN32)
|
|
HANDLE hEvents[MAXIMUM_WAIT_OBJECTS];
|
|
int rc, at_least_one_poll_set_flags_out = 0;
|
|
|
|
if(number_of_sangoma_wait_objects > MAXIMUM_WAIT_OBJECTS){
|
|
DBG_EVNT("Error: %s(): 'number_of_sangoma_wait_objects': %d is greater than the Maximum of: %d\n", __FUNCTION__,
|
|
number_of_sangoma_wait_objects, MAXIMUM_WAIT_OBJECTS);
|
|
return -1;
|
|
}
|
|
|
|
if(number_of_sangoma_wait_objects < 1){
|
|
DBG_EVNT("Error: %s(): 'number_of_sangoma_wait_objects': %d is less than the Minimum of: 1!\n", __FUNCTION__,
|
|
number_of_sangoma_wait_objects);
|
|
return -2;
|
|
}
|
|
|
|
DBG_POLL1("%s(): line: %d: number_of_sangoma_wait_objects: %d\n", __FUNCTION__, __LINE__, number_of_sangoma_wait_objects);
|
|
|
|
for(i = 0; i < number_of_sangoma_wait_objects; i++){
|
|
hEvents[i] = sangoma_wait_objects[i].SharedEvent.hEvent;
|
|
sangoma_wait_objects[i].flags_out = 0;
|
|
}
|
|
|
|
/* Note this loop is especially important for POLLOUT! */
|
|
for(i = 0; i < number_of_sangoma_wait_objects; i++){
|
|
|
|
if(sangoma_wait_objects[i].object_type == SANGOMA_WAIT_OBJ){
|
|
|
|
if(sangoma_socket_poll(&sangoma_wait_objects[i])){
|
|
return -3;
|
|
}
|
|
|
|
if(sangoma_wait_objects[i].api_poll.operation_status != SANG_STATUS_SUCCESS){
|
|
|
|
DBG_EVNT("Error: %s(): Invalid Operation Status: %s(%d)\n", __FUNCTION__,
|
|
SDLA_DECODE_SANG_STATUS(sangoma_wait_objects[i].api_poll.operation_status),
|
|
sangoma_wait_objects[i].api_poll.operation_status);
|
|
return -4;
|
|
}
|
|
|
|
if(sangoma_wait_objects[i].api_poll.poll_events_bitmap){
|
|
sangoma_wait_objects[i].flags_out = sangoma_wait_objects[i].api_poll.poll_events_bitmap;
|
|
at_least_one_poll_set_flags_out = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(at_least_one_poll_set_flags_out){
|
|
DBG_POLL1("%s(): line: %d: at_least_one_poll_set_flags_out is set\n", __FUNCTION__, __LINE__);
|
|
return 1;
|
|
}
|
|
|
|
DBG_POLL1("%s(): line: %d: going into WaitForMultipleObjects()\n", __FUNCTION__, __LINE__);
|
|
|
|
/* wait untill at least one of the events is signalled OR a 'system_wait_timeout' occured */
|
|
if(WAIT_TIMEOUT == WaitForMultipleObjects(number_of_sangoma_wait_objects, &hEvents[0], FALSE, system_wait_timeout)){
|
|
DBG_POLL1("%s(): line: %d: WaitForMultipleObjects() timedout\n", __FUNCTION__, __LINE__);
|
|
return 0;
|
|
}
|
|
|
|
DBG_POLL1("%s(): line: %d: returned from WaitForMultipleObjects()\n", __FUNCTION__, __LINE__);
|
|
|
|
/* WaitForMultipleObjects() could be waken by a Sangoma or by a non-Sangoma wait object */
|
|
for(i = 0; i < number_of_sangoma_wait_objects; i++){
|
|
|
|
if(sangoma_wait_objects[i].object_type == SANGOMA_WAIT_OBJ){
|
|
|
|
if(sangoma_socket_poll(&sangoma_wait_objects[i])){
|
|
return -5;
|
|
}
|
|
|
|
if(sangoma_wait_objects[i].api_poll.operation_status != SANG_STATUS_SUCCESS){
|
|
|
|
DBG_EVNT("Error: %s(): Invalid Operation Status: %s(%d)\n", __FUNCTION__,
|
|
SDLA_DECODE_SANG_STATUS(sangoma_wait_objects[i].api_poll.operation_status),
|
|
sangoma_wait_objects[i].api_poll.operation_status);
|
|
return -6;
|
|
}
|
|
|
|
if(sangoma_wait_objects[i].api_poll.poll_events_bitmap){
|
|
sangoma_wait_objects[i].flags_out = sangoma_wait_objects[i].api_poll.poll_events_bitmap;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 2;
|
|
#else
|
|
struct pollfd pfds[number_of_sangoma_wait_objects];
|
|
int res;
|
|
|
|
memset(pfds, 0, sizeof(pfds));
|
|
|
|
for(i = 0; i < number_of_sangoma_wait_objects; i++){
|
|
pfds[i].fd = sangoma_wait_objects[i].fd;
|
|
pfds[i].events = sangoma_wait_objects[i].flags_in;
|
|
}
|
|
|
|
res = poll(pfds, number_of_sangoma_wait_objects, system_wait_timeout);
|
|
if (res > 0) {
|
|
for(i = 0; i < number_of_sangoma_wait_objects; i++){
|
|
sangoma_wait_objects[i].flags_out = pfds[i].revents;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
#endif
|
|
}
|
|
|
|
|
|
/*!
|
|
\fn int sangoma_socket_waitfor(sangoma_wait_obj_t *sangoma_wait_obj, int timeout, int flags_in, unsigned int *flags_out)
|
|
\brief Wait for a single file descriptor - poll()
|
|
\param sangoma_wait_obj pointer to array of file descriptors to wait for
|
|
\param timeout timeout in miliseconds in case of no event
|
|
\param flags_in events to wait for (read/write/event)
|
|
\param flags_out events that occured (read/write/event)
|
|
\return negative: error, 0: timeout, positive: event occured check in *flags_out
|
|
*/
|
|
int _SAPI_CALL sangoma_socket_waitfor(sangoma_wait_obj_t *sangoma_wait_obj, int timeout, int flags_in, unsigned int *flags_out)
|
|
{
|
|
int err;
|
|
|
|
sangoma_wait_obj->flags_in = flags_in;
|
|
|
|
err = sangoma_socket_waitfor_many(sangoma_wait_obj, 1, timeout);
|
|
|
|
if(err < 0 || err == 0){
|
|
return err;
|
|
}
|
|
|
|
*flags_out = sangoma_wait_obj->flags_out;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_mgmt_cmd(sng_fd_t fd, wan_udp_hdr_t* wan_udp)
|
|
{
|
|
#if defined(__WINDOWS__)
|
|
if(DoManagementCommand(fd, wan_udp)){
|
|
return 1;
|
|
}
|
|
#else
|
|
unsigned char id = 0;
|
|
int err=0;
|
|
wan_udp->wan_udphdr_request_reply = 0x01;
|
|
wan_udp->wan_udphdr_id = id;
|
|
wan_udp->wan_udphdr_return_code = WAN_UDP_TIMEOUT_CMD;
|
|
|
|
err=ioctl(fd,WANPIPE_IOCTL_PIPEMON,wan_udp);
|
|
if (err < 0) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
if(wan_udp->wan_udphdr_return_code != WAN_CMD_OK){
|
|
return 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_span_chan_toif(int span, int chan, char *interface_name)
|
|
{
|
|
#if defined(WIN32)
|
|
/* FIXME: Not implemented */
|
|
return -1;
|
|
#else
|
|
sprintf(interface_name,"s%ic%i",span,chan);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_interface_toi(char *interface_name, int *span, int *chan)
|
|
{
|
|
char *p=NULL, *sp = NULL, *ch = NULL;
|
|
int ret = 0;
|
|
char data[FNAME_LEN];
|
|
|
|
strncpy(data, interface_name, FNAME_LEN);
|
|
if ((data[0])) {
|
|
for (p = data; *p; p++) {
|
|
if (sp && *p == 'g') {
|
|
*p = '\0';
|
|
ch = (p + 1);
|
|
break;
|
|
} else if (*p == 'w') {
|
|
sp = (p + 1);
|
|
}
|
|
}
|
|
|
|
if(ch && sp) {
|
|
*span = atoi(sp);
|
|
*chan = atoi(ch);
|
|
ret = 1;
|
|
} else {
|
|
*span = -1;
|
|
*chan = -1;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_span_chan_fromif(char *interface_name, int *span, int *chan)
|
|
{
|
|
char *p = NULL, *sp = NULL, *ch = NULL;
|
|
int ret = 0;
|
|
char data[FNAME_LEN];
|
|
|
|
strncpy(data, interface_name, FNAME_LEN);
|
|
if ((data[0])) {
|
|
for (p = data; *p; p++) {
|
|
if (sp && *p == 'c') {
|
|
*p = '\0';
|
|
ch = (p + 1);
|
|
break;
|
|
} else if (*p == 's') {
|
|
sp = (p + 1);
|
|
}
|
|
}
|
|
|
|
if(ch && sp) {
|
|
*span = atoi(sp);
|
|
*chan = atoi(ch);
|
|
ret = 1;
|
|
} else {
|
|
*span = -1;
|
|
*chan = -1;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
sng_fd_t _SAPI_CALL sangoma_open_api_span_chan(int span, int chan)
|
|
{
|
|
sng_fd_t fd = INVALID_HANDLE_VALUE;
|
|
wanpipe_api_t tdm_api;
|
|
int err;
|
|
|
|
fd = __sangoma_open_api_span_chan(span, chan);
|
|
|
|
#if defined(__WINDOWS__)
|
|
if(fd == INVALID_HANDLE_VALUE){
|
|
//DBG_EVNT("Span: %d, chan: %d: is not running, consider 'busy'\n", span, chan);
|
|
return fd;
|
|
}
|
|
#else
|
|
if (fd < 0) {
|
|
return fd;
|
|
}
|
|
#endif
|
|
|
|
memset(&tdm_api,0,sizeof(tdm_api));
|
|
tdm_api.wp_cmd.cmd = WP_API_CMD_OPEN_CNT;
|
|
err=sangoma_cmd_exec(fd,&tdm_api);
|
|
if (err){
|
|
sangoma_close(&fd);
|
|
return fd;
|
|
}
|
|
|
|
if (tdm_api.wp_cmd.open_cnt > 1) {
|
|
/* this is NOT the first open request for this span/chan */
|
|
sangoma_close(&fd);
|
|
fd = INVALID_HANDLE_VALUE;/* fd is NOT valid anymore */
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
/* no checks done for multiple open */
|
|
sng_fd_t _SAPI_CALL __sangoma_open_api_span_chan(int span, int chan)
|
|
{
|
|
char fname[FNAME_LEN], tmp_fname[FNAME_LEN];
|
|
|
|
/* Form the Interface Name from span and chan number (i.e. wanpipe1_if1). */
|
|
_snprintf(tmp_fname, DEV_NAME_LEN, WP_INTERFACE_NAME_FORM, span, chan);
|
|
|
|
#if defined(WIN32)
|
|
_snprintf(fname , FNAME_LEN, "\\\\.\\%s", tmp_fname);
|
|
return CreateFile( fname,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
(LPSECURITY_ATTRIBUTES)NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
|
|
(HANDLE)NULL
|
|
);
|
|
#else
|
|
//sprintf(fname,"/dev/wanpipe%d_if%d",span,chan);
|
|
sprintf(fname,"/dev/%s", tmp_fname);
|
|
|
|
return open(fname, O_RDWR);
|
|
#endif
|
|
}
|
|
|
|
sng_fd_t sangoma_open_api_ctrl(void)
|
|
{
|
|
#if defined(WIN32)
|
|
sng_fd_t fd = INVALID_HANDLE_VALUE;
|
|
|
|
#pragma message("sangoma_open_api_ctrl: Not support on Windows")
|
|
#else
|
|
sng_fd_t fd=-1;
|
|
|
|
fd = open("/dev/wanpipe_ctrl", O_RDWR);
|
|
#endif
|
|
|
|
return fd;
|
|
}
|
|
|
|
sng_fd_t _SAPI_CALL sangoma_create_socket_by_name(char *device, char *card)
|
|
{
|
|
int span,chan;
|
|
sangoma_interface_toi(device,&span,&chan);
|
|
|
|
return sangoma_open_api_span_chan(span,chan);
|
|
}
|
|
|
|
|
|
sng_fd_t _SAPI_CALL sangoma_open_api_span(int span)
|
|
{
|
|
int i=0;
|
|
sng_fd_t fd = INVALID_HANDLE_VALUE;
|
|
|
|
for(i = 1; i < 32; i++){
|
|
|
|
fd = sangoma_open_api_span_chan(span, i);
|
|
|
|
#if defined(WIN32)
|
|
if(fd != INVALID_HANDLE_VALUE){
|
|
#else
|
|
if (fd >= 0) {
|
|
#endif
|
|
|
|
//found free chan
|
|
break;
|
|
}
|
|
|
|
}//for()
|
|
|
|
return fd;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_readmsg(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, int datalen, int flag)
|
|
{
|
|
int rx_len=0;
|
|
|
|
#if defined(WIN32)
|
|
wp_api_hdr_t *rx_hdr = (wp_api_hdr_t*)hdrbuf;
|
|
wp_api_element_t wp_api_element;
|
|
|
|
if(hdrlen != sizeof(wp_api_hdr_t)){
|
|
//error
|
|
DBG_EVNT("Error: %s(): invalid size of user's 'header buffer'. Should be 'sizeof(wp_api_hdr_t)'.\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if(DoReadCommand(fd, &wp_api_element)){
|
|
//error
|
|
DBG_EVNT("Error: %s(): DoReadCommand() failed! Check messages log.\n", __FUNCTION__);
|
|
return -4;
|
|
}
|
|
|
|
memcpy(rx_hdr, &wp_api_element.hdr, sizeof(wp_api_hdr_t));
|
|
|
|
switch(rx_hdr->operation_status)
|
|
{
|
|
case SANG_STATUS_RX_DATA_AVAILABLE:
|
|
/* ok */
|
|
if(rx_hdr->data_length <= datalen){
|
|
memcpy(databuf, wp_api_element.data, rx_hdr->data_length);
|
|
}else{
|
|
rx_hdr->operation_status = SANG_STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
break;
|
|
default:
|
|
/* note that SANG_STATUS_DEVICE_BUSY is NOT an error! */
|
|
if(0)DBG_EVNT("Error: %s(): Operation Status: %s(%d)\n", __FUNCTION__,
|
|
SDLA_DECODE_SANG_STATUS(rx_hdr->operation_status), rx_hdr->operation_status);
|
|
return -5;
|
|
}
|
|
|
|
rx_len = rx_hdr->data_length;
|
|
#else
|
|
struct msghdr msg;
|
|
struct iovec iov[2];
|
|
|
|
memset(&msg,0,sizeof(struct msghdr));
|
|
|
|
iov[0].iov_len=hdrlen;
|
|
iov[0].iov_base=hdrbuf;
|
|
|
|
iov[1].iov_len=datalen;
|
|
iov[1].iov_base=databuf;
|
|
|
|
msg.msg_iovlen=2;
|
|
msg.msg_iov=iov;
|
|
|
|
rx_len = read(fd,&msg,datalen+hdrlen);
|
|
|
|
if (rx_len <= sizeof(wp_api_hdr_t)){
|
|
return -EINVAL;
|
|
}
|
|
|
|
rx_len-=sizeof(wp_api_hdr_t);
|
|
#endif
|
|
return rx_len;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_writemsg(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, unsigned short datalen, int flag)
|
|
{
|
|
int bsent=-1;
|
|
wp_api_hdr_t *wp_api_hdr = hdrbuf;
|
|
|
|
if (hdrlen != sizeof(wp_api_hdr_t)) {
|
|
DBG_ERR("Error: sangoma_writemsg() failed! hdrlen (%i) != sizeof(wp_api_hdr_t) (%i)\n",
|
|
hdrlen,sizeof(wp_api_hdr_t));
|
|
wp_api_hdr->operation_status = SANG_STATUS_TX_HDR_TOO_SHORT;
|
|
return -1;
|
|
}
|
|
|
|
#if defined(WIN32)
|
|
//queue data for transmission
|
|
if(DoWriteCommand(fd, databuf, datalen, hdrbuf, hdrlen)){
|
|
//error
|
|
DBG_EVNT("Error: DoWriteCommand() failed!! Check messages log.\n");
|
|
return -1;
|
|
}
|
|
|
|
bsent=0;
|
|
//check that frame was transmitted
|
|
switch(wp_api_hdr->operation_status)
|
|
{
|
|
case SANG_STATUS_SUCCESS:
|
|
bsent = datalen;
|
|
break;
|
|
default:
|
|
DBG_EVNT("Error: %s(): Operation Status: %s(%d)\n", __FUNCTION__,
|
|
SDLA_DECODE_SANG_STATUS(wp_api_hdr->operation_status), wp_api_hdr->operation_status);
|
|
break;
|
|
}//switch()
|
|
#else
|
|
struct msghdr msg;
|
|
struct iovec iov[2];
|
|
wp_api_hdr_t *tx_el=hdrbuf;
|
|
|
|
memset(&msg,0,sizeof(struct msghdr));
|
|
|
|
iov[0].iov_len=hdrlen;
|
|
iov[0].iov_base=hdrbuf;
|
|
|
|
iov[1].iov_len=datalen;
|
|
iov[1].iov_base=databuf;
|
|
|
|
msg.msg_iovlen=2;
|
|
msg.msg_iov=iov;
|
|
|
|
bsent = write(fd,&msg,datalen+hdrlen);
|
|
|
|
if (bsent == (datalen+hdrlen)){
|
|
tx_el->wp_api_hdr_operation_status=SANG_STATUS_SUCCESS;
|
|
bsent-=sizeof(wp_api_hdr_t);
|
|
} else if (errno == EBUSY){
|
|
tx_el->wp_api_hdr_operation_status=SANG_STATUS_DEVICE_BUSY;
|
|
} else {
|
|
tx_el->wp_api_hdr_operation_status=SANG_STATUS_IO_ERROR;
|
|
}
|
|
tx_el->wp_api_hdr_data_length=bsent;
|
|
#endif
|
|
return bsent;
|
|
}
|
|
|
|
|
|
#ifdef WANPIPE_TDM_API
|
|
|
|
/*========================================================
|
|
* Execute TDM command
|
|
*
|
|
*/
|
|
int _SAPI_CALL sangoma_cmd_exec(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
#if defined(WIN32)
|
|
err = tdmv_api_ioctl(fd, &tdm_api->wp_cmd);
|
|
#else
|
|
err = ioctl(fd,SIOC_WANPIPE_TDM_API,&tdm_api->wp_cmd);
|
|
if (err < 0){
|
|
char tmp[50];
|
|
sprintf(tmp,"TDM API: CMD: %i\n",tdm_api->wp_cmd.cmd);
|
|
perror(tmp);
|
|
return -1;
|
|
}
|
|
#endif
|
|
return err;
|
|
}
|
|
|
|
/*========================================================
|
|
* Get Full TDM API configuration per channel
|
|
*
|
|
*/
|
|
int _SAPI_CALL sangoma_get_full_cfg(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_FULL_CFG;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
#if 1
|
|
printf("TDM API CFG:\n");
|
|
printf("\thw_tdm_coding:\t%d\n",tdm_api->wp_cmd.hw_tdm_coding);
|
|
printf("\thw_mtu_mru:\t%d\n",tdm_api->wp_cmd.hw_mtu_mru);
|
|
printf("\tusr_period:\t%d\n",tdm_api->wp_cmd.usr_period);
|
|
printf("\ttdm_codec:\t%d\n",tdm_api->wp_cmd.tdm_codec);
|
|
printf("\tpower_level:\t%d\n",tdm_api->wp_cmd.power_level);
|
|
printf("\trx_disable:\t%d\n",tdm_api->wp_cmd.rx_disable);
|
|
printf("\ttx_disable:\t%d\n",tdm_api->wp_cmd.tx_disable);
|
|
printf("\tusr_mtu_mru:\t%d\n",tdm_api->wp_cmd.usr_mtu_mru);
|
|
printf("\tidle flag:\t0x%02X\n",tdm_api->wp_cmd.idle_flag);
|
|
|
|
#ifdef WP_API_FEATURE_FE_ALARM
|
|
printf("\tfe alarms:\t0x%02X\n",tdm_api->wp_cmd.fe_alarms);
|
|
#endif
|
|
|
|
printf("\trx pkt\t%d\ttx pkt\t%d\n",tdm_api->wp_cmd.stats.rx_packets,
|
|
tdm_api->wp_cmd.stats.tx_packets);
|
|
printf("\trx err\t%d\ttx err\t%d\n",
|
|
tdm_api->wp_cmd.stats.rx_errors,
|
|
tdm_api->wp_cmd.stats.tx_errors);
|
|
#ifndef __WINDOWS__
|
|
printf("\trx ovr\t%d\ttx idl\t%d\n",
|
|
tdm_api->wp_cmd.stats.rx_fifo_errors,
|
|
tdm_api->wp_cmd.stats.tx_carrier_errors);
|
|
#endif
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*========================================================
|
|
* SET Codec on a particular Channel.
|
|
*
|
|
* Available codecs are defined in
|
|
* /usr/src/linux/include/linux/wanpipe_cfg.h
|
|
*
|
|
* enum wan_codec_format {
|
|
* WP_NONE,
|
|
* WP_SLINEAR
|
|
* }
|
|
*
|
|
*/
|
|
int _SAPI_CALL sangoma_tdm_set_codec(sng_fd_t fd, wanpipe_api_t *tdm_api, int codec)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_CODEC;
|
|
tdm_api->wp_cmd.tdm_codec = codec;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*========================================================
|
|
* GET Codec from a particular Channel.
|
|
*
|
|
* Available codecs are defined in
|
|
* /usr/src/linux/include/linux/wanpipe_cfg.h
|
|
*
|
|
* enum wan_codec_format {
|
|
* WP_NONE,
|
|
* WP_SLINEAR
|
|
* }
|
|
*
|
|
*/
|
|
int _SAPI_CALL sangoma_tdm_get_codec(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_CODEC;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.tdm_codec;
|
|
}
|
|
|
|
/*========================================================
|
|
* SET Rx/Tx Hardware Period in milliseconds.
|
|
*
|
|
* Available options are:
|
|
* 10,20,30,40,50 ms
|
|
*
|
|
*/
|
|
int _SAPI_CALL sangoma_tdm_set_usr_period(sng_fd_t fd, wanpipe_api_t *tdm_api, int period)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_USR_PERIOD;
|
|
tdm_api->wp_cmd.usr_period = period;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*========================================================
|
|
* GET Rx/Tx Hardware Period in milliseconds.
|
|
*
|
|
* Available options are:
|
|
* 10,20,30,40,50 ms
|
|
*
|
|
*/
|
|
int _SAPI_CALL sangoma_tdm_get_usr_period(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_USR_PERIOD;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.usr_period;
|
|
}
|
|
|
|
/*========================================================
|
|
* GET Current User Hardware Coding Format
|
|
*
|
|
* Coding Format will be ULAW/ALAW based on T1/E1
|
|
*/
|
|
|
|
int _SAPI_CALL sangoma_get_hw_coding(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_HW_CODING;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
return tdm_api->wp_cmd.hw_tdm_coding;
|
|
}
|
|
|
|
#ifdef WP_API_FEATURE_DTMF_EVENTS
|
|
/*========================================================
|
|
* GET Current User Hardware DTMF Enabled/Disabled
|
|
*
|
|
* Will return true if HW DTMF is enabled on Octasic
|
|
*/
|
|
|
|
int _SAPI_CALL sangoma_tdm_get_hw_dtmf(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_HW_DTMF;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
return tdm_api->wp_cmd.hw_dtmf;
|
|
}
|
|
#endif
|
|
|
|
/*========================================================
|
|
* GET Current User MTU/MRU values in bytes.
|
|
*
|
|
* The USER MTU/MRU values will change each time a PERIOD
|
|
* or CODEC is adjusted.
|
|
*/
|
|
int _SAPI_CALL sangoma_tdm_get_usr_mtu_mru(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_USR_MTU_MRU;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.usr_mtu_mru;
|
|
}
|
|
|
|
/*========================================================
|
|
* SET TDM Power Level
|
|
*
|
|
* This option is not implemented yet
|
|
*
|
|
*/
|
|
int _SAPI_CALL sangoma_tdm_set_power_level(sng_fd_t fd, wanpipe_api_t *tdm_api, int power)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_POWER_LEVEL;
|
|
tdm_api->wp_cmd.power_level = power;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*========================================================
|
|
* GET TDM Power Level
|
|
*
|
|
* This option is not implemented yet
|
|
*
|
|
*/
|
|
int _SAPI_CALL sangoma_tdm_get_power_level(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_POWER_LEVEL;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.power_level;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_flush_bufs(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_FLUSH_BUFFERS;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_enable_rbs_events(sng_fd_t fd, wanpipe_api_t *tdm_api, int poll_in_sec) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_ENABLE_RBS_EVENTS;
|
|
tdm_api->wp_cmd.rbs_poll=poll_in_sec;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.rbs_poll;
|
|
}
|
|
|
|
|
|
int _SAPI_CALL sangoma_tdm_disable_rbs_events(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_DISABLE_RBS_EVENTS;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_write_rbs(sng_fd_t fd, wanpipe_api_t *tdm_api, unsigned char rbs)
|
|
{
|
|
|
|
int err;
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_WRITE_RBS_BITS;
|
|
tdm_api->wp_cmd.rbs_tx_bits=rbs;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_read_event(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
|
|
#ifdef WP_API_FEATURE_EVENTS
|
|
wp_api_event_t *rx_event;
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_READ_EVENT;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
rx_event = &tdm_api->wp_cmd.event;
|
|
|
|
|
|
/*
|
|
The use of callbacks here is purely optional and is left
|
|
here for backward compatibility purposes. By default user
|
|
should handle events outside this funciton. This function
|
|
should only be used to read the event
|
|
*/
|
|
|
|
switch (rx_event->wp_api_event_type){
|
|
|
|
case WP_API_EVENT_RBS:
|
|
if (tdm_api->wp_callback.wp_rbs_event) {
|
|
tdm_api->wp_callback.wp_rbs_event(fd,rx_event->wp_api_event_rbs_bits);
|
|
}
|
|
|
|
break;
|
|
|
|
#ifdef WP_API_FEATURE_DTMF_EVENTS
|
|
case WP_API_EVENT_DTMF:
|
|
if (tdm_api->wp_callback.wp_dtmf_event) {
|
|
tdm_api->wp_callback.wp_dtmf_event(fd,
|
|
rx_event->wp_api_event_dtmf_digit,
|
|
rx_event->wp_api_event_dtmf_type,
|
|
rx_event->wp_api_event_dtmf_port);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case WP_API_EVENT_RXHOOK:
|
|
if (tdm_api->wp_callback.wp_rxhook_event) {
|
|
tdm_api->wp_callback.wp_rxhook_event(fd,
|
|
rx_event->wp_api_event_hook_state);
|
|
}
|
|
break;
|
|
|
|
case WP_API_EVENT_RING_DETECT:
|
|
if (tdm_api->wp_callback.wp_ring_detect_event) {
|
|
tdm_api->wp_callback.wp_ring_detect_event(fd,
|
|
rx_event->wp_api_event_ring_state);
|
|
}
|
|
break;
|
|
|
|
case WP_API_EVENT_RING_TRIP_DETECT:
|
|
if (tdm_api->wp_callback.wp_ring_trip_detect_event) {
|
|
tdm_api->wp_callback.wp_ring_trip_detect_event(fd,
|
|
rx_event->wp_api_event_ring_state);
|
|
}
|
|
break;
|
|
|
|
#ifdef WP_API_FEATURE_FE_ALARM
|
|
case WP_API_EVENT_ALARM:
|
|
if (tdm_api->wp_callback.wp_fe_alarm_event) {
|
|
tdm_api->wp_callback.wp_fe_alarm_event(fd,
|
|
rx_event->wp_api_event_alarm);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifdef WP_API_FEATURE_LINK_STATUS
|
|
/* Link Status */
|
|
case WP_API_EVENT_LINK_STATUS:
|
|
if(tdm_api->wp_callback.wp_link_status_event){
|
|
tdm_api->wp_callback.wp_link_status_event(fd,
|
|
rx_event->wp_api_event_link_status);
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
default:
|
|
printf("%d: Unknown TDM event!", (int)fd);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
#else
|
|
printf("Error: Read Event not supported!\n");
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
#ifdef WP_API_FEATURE_DTMF_EVENTS
|
|
int _SAPI_CALL sangoma_tdm_enable_dtmf_events(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_DTMF;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_disable_dtmf_events(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_DTMF;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_DISABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_enable_rm_dtmf_events(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RM_DTMF;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_disable_rm_dtmf_events(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RM_DTMF;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_DISABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_enable_rxhook_events(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RXHOOK;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_disable_rxhook_events(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RXHOOK;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_DISABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_enable_ring_events(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RING;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int _SAPI_CALL sangoma_tdm_disable_ring_events(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RING;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_DISABLE;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_enable_ring_detect_events(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RING_DETECT;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
int _SAPI_CALL sangoma_tdm_disable_ring_detect_events(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RING_DETECT;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_DISABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_enable_ring_trip_detect_events(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RING_TRIP_DETECT;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.rbs_poll;
|
|
}
|
|
|
|
|
|
int _SAPI_CALL sangoma_tdm_disable_ring_trip_detect_events(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_RING_DETECT;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_DISABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_txsig_kewl(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_TXSIG_KEWL;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_txsig_start(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_TXSIG_START;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_txsig_onhook(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_TXSIG_ONHOOK;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_txsig_offhook(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_TXSIG_OFFHOOK;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int _SAPI_CALL sangoma_tdm_enable_tone_events(sng_fd_t fd, wanpipe_api_t *tdm_api, uint16_t tone_id) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_TONE;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_ENABLE;
|
|
tdm_api->wp_cmd.event.wp_api_event_tone_type = tone_id;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.rbs_poll;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_disable_tone_events(sng_fd_t fd, wanpipe_api_t *tdm_api) {
|
|
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_EVENT;
|
|
tdm_api->wp_cmd.event.wp_api_event_type = WP_API_EVENT_TONE;
|
|
tdm_api->wp_cmd.event.wp_api_event_mode = WP_API_EVENT_DISABLE;
|
|
tdm_api->wp_cmd.event.wp_api_event_tone_type = 0x00;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.rbs_poll;
|
|
}
|
|
|
|
#endif
|
|
|
|
int _SAPI_CALL sangoma_tdm_enable_hwec(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_ENABLE_HWEC;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_tdm_disable_hwec(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_DISABLE_HWEC;
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*========================================================
|
|
* GET Front End Alarms
|
|
*
|
|
*/
|
|
#ifdef WP_API_FEATURE_FE_ALARM
|
|
int _SAPI_CALL sangoma_tdm_get_fe_alarms(sng_fd_t fd, wanpipe_api_t *tdm_api, unsigned int *alarms)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_FE_ALARMS;
|
|
|
|
err=sangoma_cmd_exec(fd,tdm_api);
|
|
if (err){
|
|
return err;
|
|
}
|
|
|
|
*alarms=tdm_api->wp_cmd.fe_alarms;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* get current Line Connection state - Connected/Disconnected */
|
|
int _SAPI_CALL sangoma_get_fe_status(sng_fd_t fd, wanpipe_api_t *tdm_api, unsigned char *current_status)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_FE_STATUS;
|
|
err = sangoma_cmd_exec(fd, tdm_api);
|
|
*current_status = tdm_api->wp_cmd.fe_status;
|
|
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
/* get current Line Connection state - Connected/Disconnected */
|
|
#ifdef WP_API_FEATURE_LINK_STATUS
|
|
int _SAPI_CALL sangoma_get_link_status(sng_fd_t fd, wanpipe_api_t *tdm_api, unsigned char *current_status)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_FE_STATUS;
|
|
err = sangoma_cmd_exec(fd, tdm_api);
|
|
*current_status = tdm_api->wp_cmd.fe_status;
|
|
|
|
return err;
|
|
}
|
|
|
|
/* set current Line Connection state - Connected/Disconnected. valid only for ISDN BRI */
|
|
int _SAPI_CALL sangoma_set_fe_status(sng_fd_t fd, wanpipe_api_t *tdm_api, unsigned char new_status)
|
|
{
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_FE_STATUS;
|
|
tdm_api->wp_cmd.fe_status = new_status;
|
|
|
|
return sangoma_cmd_exec(fd, tdm_api);
|
|
}
|
|
#endif
|
|
|
|
int _SAPI_CALL sangoma_get_tx_queue_sz(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_TX_Q_SIZE;
|
|
tdm_api->wp_cmd.tx_queue_sz = 0;
|
|
|
|
err=sangoma_cmd_exec(fd, tdm_api);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.tx_queue_sz;
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_set_tx_queue_sz(sng_fd_t fd, wanpipe_api_t *tdm_api, int size)
|
|
{
|
|
if (size < 0) {
|
|
return -1;
|
|
}
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_TX_Q_SIZE;
|
|
tdm_api->wp_cmd.tx_queue_sz = size;
|
|
|
|
return sangoma_cmd_exec(fd, tdm_api);
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_get_rx_queue_sz(sng_fd_t fd, wanpipe_api_t *tdm_api)
|
|
{
|
|
int err;
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_GET_RX_Q_SIZE;
|
|
tdm_api->wp_cmd.rx_queue_sz = 0;
|
|
|
|
err=sangoma_cmd_exec(fd, tdm_api);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
|
|
return tdm_api->wp_cmd.rx_queue_sz;
|
|
|
|
}
|
|
|
|
int _SAPI_CALL sangoma_set_rx_queue_sz(sng_fd_t fd, wanpipe_api_t *tdm_api, int size)
|
|
{
|
|
if (size < 0) {
|
|
return -1;
|
|
}
|
|
|
|
tdm_api->wp_cmd.cmd = WP_API_CMD_SET_RX_Q_SIZE;
|
|
tdm_api->wp_cmd.rx_queue_sz = size;
|
|
|
|
return sangoma_cmd_exec(fd, tdm_api);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* WANPIPE_TDM_API */
|