1290 lines
47 KiB
C++
1290 lines
47 KiB
C++
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \file SangomaPort.cpp
|
|
/// \brief This file contains the implementation of the SangomaPort class
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if defined(__WINDOWS__)
|
|
# ifndef _DEBUG
|
|
# pragma optimize("2gt",on) // Windows specific (MS_SPECIFIC), enables optimization in Release mode
|
|
# endif
|
|
#endif
|
|
|
|
#include <sstream>
|
|
#include <time.h>
|
|
#include "SangomaPort.h"
|
|
#include "driver_configurator.h"
|
|
|
|
#define DBG_PORT if(0)printf
|
|
#define INFO_PORT if(0)printf
|
|
//This macro is for Error reporting and should NOT be disabled.
|
|
#define ERR_PORT printf("Error:%s():line:%d: ", __FUNCTION__, __LINE__);printf
|
|
|
|
#define DBG_OPEN if(0)printf
|
|
#define PORT_FUNC() if(0)printf("%s(): Line: %u\n", __FUNCTION__, __LINE__)
|
|
|
|
extern void print_data_buffer(unsigned char *buffer, int buffer_length);
|
|
|
|
using namespace Sangoma;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn Configuration::Configuration()
|
|
/// \brief Constructor (for the Configuration structure)
|
|
/// \author J. Markwordt
|
|
/// \date 10/04/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
Configuration::Configuration()
|
|
: e1Ort1(E1),
|
|
Framing(E1_CAS_CRC4_ON),
|
|
lineCoding(OFF),
|
|
HighImpedanceMode(true),
|
|
TxTristateMode(false)
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn Statistics::Statistics()
|
|
/// \brief Constructor (for the Statistics structure)
|
|
/// \author J. Markwordt
|
|
/// \date 10/04/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
Statistics::Statistics()
|
|
: TimeLastOpened(0),
|
|
TimeLastClosed(0),
|
|
TimeLastFoundSync(0),
|
|
TimeLastLostSync(0),
|
|
OpenCount(0),
|
|
CloseCount(0),
|
|
FoundSyncCount(0),
|
|
LostSyncCount(0),
|
|
BytesReceived(0),
|
|
BytesSent(0)
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn Alarms::Alarms()
|
|
/// \brief Constructor (for the Alarms structure)
|
|
/// \author J. Markwordt
|
|
/// \date 10/19/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
Alarms::Alarms()
|
|
: LossOfSignal(false),
|
|
ReceiveLossOfSignal(false),
|
|
AlternateLossOfSignalStatus(false),
|
|
OutOfFrame(false),
|
|
Red(false),
|
|
AlarmIndicationSignal(false),
|
|
LossOfSignalingMultiframe(false),
|
|
LossOfCrcMultiframe(false),
|
|
OutOfOfflineFrame(false),
|
|
ReceiveLossOfSignalV(false),
|
|
Yellow(false)
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn DriverVersion::DriverVersion()
|
|
/// \brief Constructor (for the DriverVersion structure)
|
|
/// \author J. Markwordt
|
|
/// \date 10/19/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
DriverVersion::DriverVersion()
|
|
: Major(0),
|
|
Minor(0),
|
|
Build(0),
|
|
Revision(0)
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn PortEvent::PortEvent()
|
|
/// \brief Constructor (for the PortEvent structure)
|
|
/// \author J. Markwordt
|
|
/// \date 10/18/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
PortEvent::PortEvent()
|
|
: EventType(Unsignalled),
|
|
EventHandle(NULL)
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::SangomaPort(const unsigned int card_number, const unsigned int port_number,
|
|
/// const PortEvent & event, const BufferSettings & ReceiveBufferSettings,
|
|
/// const BufferSettings & TransmitBufferSettings)
|
|
/// \brief Constructor
|
|
///
|
|
/// Sets the size and number of the port's buffers for transmit and recieve (see the
|
|
/// BufferSettings structure for more details). Receive or transmit can be disabled,
|
|
/// allowing more resources to be devoted to the other direction by setting the
|
|
/// NumberOfBuffersPerPort for their respective BufferSettings structures.
|
|
/// \param card_number unsigned int number of the SangomaCard that this port is part of
|
|
/// (zero indexed)
|
|
/// \param port_number unsigned int number of the port that this object represents
|
|
/// (this is relative to the card and zero indexed, so the first
|
|
/// port of both card 1 and 2 will be 0)
|
|
/// \param event PortEvent structure to signal port events with (contains HANDLE
|
|
/// to signal the event with and EventType to set indicating the type of event)
|
|
/// \param ReceiveBufferSettings BufferSettings to configure the host memory buffers
|
|
/// for receive operations on this port (set NumberOfBuffersPerPort
|
|
/// to 0 to disable receiving data on this port)
|
|
/// \param TransmitBufferSettings BufferSettings to configure the host memory buffers
|
|
/// for transmit operations on this port (set NumberOfBuffersPerPort
|
|
/// to 0 to disable transmitting data on this port)
|
|
/// \author J. Markwordt
|
|
/// \date 10/04/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
SangomaPort::SangomaPort(const unsigned int card_number, const unsigned int port_number,
|
|
const BufferSettings & ReceiveBufferSettings,
|
|
const BufferSettings & TransmitBufferSettings)
|
|
: CardNumber(card_number),
|
|
PortNumber(port_number),
|
|
IsOpen(false),
|
|
CurrentConfiguration(),
|
|
PortStatistics()
|
|
{
|
|
PORT_FUNC();
|
|
|
|
LastError = NO_ERROR_OCCURRED;
|
|
|
|
DBG_PORT("%s(): card_number: %u, port_number: %u\n", __FUNCTION__, card_number, port_number);
|
|
|
|
InitializeCriticalSection(&cs_CriticalSection);
|
|
|
|
SangomaInterface = new sangoma_interface(CardNumber, PortNumber);
|
|
DBG_PORT("SangomaInterface: 0x%p\n", SangomaInterface);
|
|
|
|
this->ReceiveBufferSettings = ReceiveBufferSettings;
|
|
this->TransmitBufferSettings = TransmitBufferSettings;
|
|
|
|
// Calculate the size of a host memory buffer by multiplying the maximum buffer size as defined
|
|
// by the Sangoma API by a multiplier (buffer_multiplier_factor) for both the receive and transmit buffers
|
|
ReceiveBuffer = new PortBuffer(sizeof(RX_DATA_STRUCT) * ReceiveBufferSettings.BufferMultiplierFactor);
|
|
TransmitBuffer = new PortBuffer(sizeof(TX_DATA_STRUCT) * TransmitBufferSettings.BufferMultiplierFactor);
|
|
|
|
pTxFile = NULL;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::~SangomaPort()
|
|
/// \brief Destructor
|
|
/// \author J. Markwordt
|
|
/// \date 10/04/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
SangomaPort::~SangomaPort()
|
|
{
|
|
PORT_FUNC();
|
|
//EnterPortCriticalSection();
|
|
//LeavePortCriticalSection();
|
|
//PORT_FUNC();
|
|
|
|
// If the has not been properly closed, close it
|
|
if (IsOpen) {
|
|
Close();
|
|
}
|
|
|
|
// Deallocate Rx/Tx Port buffers
|
|
delete ReceiveBuffer;
|
|
delete TransmitBuffer;
|
|
|
|
if(SangomaInterface != NULL){
|
|
delete SangomaInterface;
|
|
SangomaInterface = NULL;
|
|
}
|
|
|
|
if (pTxFile) {
|
|
fclose( pTxFile );
|
|
}
|
|
|
|
PORT_FUNC();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::~SangomaPort(const Configuration & config)
|
|
/// \brief Implementation of Sangoma's low level API call to set port configuration - T1/E1.
|
|
/// \author David Rokhvarg
|
|
/// \date 11/08/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
int SangomaPort::SetPortConfiguration(const Configuration & config)
|
|
{
|
|
int return_code;
|
|
sdla_fe_cfg_t sdla_fe_cfg;
|
|
buffer_settings_t buffer_settings;
|
|
std::ostringstream error_msg;
|
|
|
|
driver_configurator *p_drv_cfg_obj = new driver_configurator();
|
|
if(p_drv_cfg_obj->init(CardNumber, SangomaInterface->get_mapped_port_number())){
|
|
error_msg << "ERROR: " << __FUNCTION__ << "(): failed to initialize Sangoma Driver Configuration object";
|
|
LastError = error_msg.str();
|
|
delete p_drv_cfg_obj;
|
|
return 1;
|
|
}
|
|
|
|
memset(&sdla_fe_cfg, 0x00, sizeof(sdla_fe_cfg_t));
|
|
switch(config.e1Ort1)
|
|
{
|
|
case T1:
|
|
FE_LBO(&sdla_fe_cfg) = WAN_T1_LBO_0_DB;//important to set to a valid value for both T1 and E1!!
|
|
FE_MEDIA(&sdla_fe_cfg) = WAN_MEDIA_T1;
|
|
switch(config.lineCoding)
|
|
{
|
|
case OFF:
|
|
FE_LCODE(&sdla_fe_cfg) = WAN_LCODE_AMI;
|
|
break;
|
|
case ON:
|
|
FE_LCODE(&sdla_fe_cfg) = WAN_LCODE_B8ZS;
|
|
break;
|
|
default:
|
|
error_msg << "ERROR: " << __FUNCTION__ << "(): T1 invalid lineCoding " << config.lineCoding;
|
|
LastError = error_msg.str();
|
|
delete p_drv_cfg_obj;
|
|
return 1;
|
|
}
|
|
|
|
switch(config.Framing)
|
|
{
|
|
case T1_EXTENDED_SUPERFRAME:
|
|
FE_FRAME(&sdla_fe_cfg) = WAN_FR_ESF;
|
|
break;
|
|
case T1_SUPERFRAME:
|
|
FE_FRAME(&sdla_fe_cfg) = WAN_FR_D4;
|
|
break;
|
|
default:
|
|
error_msg << "ERROR: " << __FUNCTION__ << "(): T1: invalid Framing " << config.Framing;
|
|
LastError = error_msg.str();
|
|
delete p_drv_cfg_obj;
|
|
return 1;
|
|
}
|
|
|
|
FE_SIG_MODE(&sdla_fe_cfg) = WAN_TE1_SIG_CCS;
|
|
FE_LBO(&sdla_fe_cfg) = WAN_T1_LBO_0_DB;
|
|
//320*24=7680
|
|
TxMtu = 7680;
|
|
break;
|
|
|
|
case E1:
|
|
FE_LBO(&sdla_fe_cfg) = WAN_E1_120;//important to set to a valid value for both T1 and E1!!
|
|
FE_MEDIA(&sdla_fe_cfg) = WAN_MEDIA_E1;
|
|
switch(config.lineCoding)
|
|
{
|
|
case OFF:
|
|
FE_LCODE(&sdla_fe_cfg) = WAN_LCODE_AMI;
|
|
break;
|
|
case ON:
|
|
FE_LCODE(&sdla_fe_cfg) = WAN_LCODE_HDB3;
|
|
break;
|
|
default:
|
|
error_msg << "ERROR: " << __FUNCTION__ << "(): E1 invalid lineCoding " << config.lineCoding;
|
|
LastError = error_msg.str();
|
|
delete p_drv_cfg_obj;
|
|
return 1;
|
|
}
|
|
|
|
//FE_FRAME(&sdla_fe_cfg) = WAN_FR_CRC4;
|
|
switch(config.Framing)
|
|
{
|
|
case E1_CAS_CRC4_ON:
|
|
FE_FRAME(&sdla_fe_cfg) = WAN_FR_CRC4;
|
|
FE_SIG_MODE(&sdla_fe_cfg) = WAN_TE1_SIG_CAS;
|
|
//240*31=7440
|
|
TxMtu = 7440;
|
|
break;
|
|
case E1_CAS_CRC4_OFF:
|
|
FE_FRAME(&sdla_fe_cfg) = WAN_FR_NCRC4;
|
|
FE_SIG_MODE(&sdla_fe_cfg) = WAN_TE1_SIG_CAS;
|
|
//240*31=7440
|
|
TxMtu = 7440;
|
|
break;
|
|
case E1_CCS_CRC4_ON:
|
|
FE_FRAME(&sdla_fe_cfg) = WAN_FR_CRC4;
|
|
FE_SIG_MODE(&sdla_fe_cfg) = WAN_TE1_SIG_CCS;
|
|
//240*31=7440
|
|
TxMtu = 7440;
|
|
break;
|
|
case E1_CCS_CRC4_OFF:
|
|
FE_FRAME(&sdla_fe_cfg) = WAN_FR_NCRC4;
|
|
FE_SIG_MODE(&sdla_fe_cfg) = WAN_TE1_SIG_CCS;
|
|
//240*31=7440
|
|
TxMtu = 7440;
|
|
break;
|
|
|
|
case E1_CAS_UNFRAMED:
|
|
FE_FRAME(&sdla_fe_cfg) = WAN_FR_UNFRAMED;
|
|
FE_SIG_MODE(&sdla_fe_cfg) = WAN_TE1_SIG_CAS;
|
|
//240*32=7680
|
|
TxMtu = 7680;
|
|
break;
|
|
case E1_CCS_UNFRAMED:
|
|
FE_FRAME(&sdla_fe_cfg) = WAN_FR_UNFRAMED;
|
|
FE_SIG_MODE(&sdla_fe_cfg) = WAN_TE1_SIG_CCS;
|
|
//240*32=7680
|
|
TxMtu = 7680;
|
|
break;
|
|
|
|
default:
|
|
error_msg << "ERROR: " << __FUNCTION__ << "(): E1: invalid Framing " << config.Framing;
|
|
LastError = error_msg.str();
|
|
delete p_drv_cfg_obj;
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
error_msg << "ERROR: " << __FUNCTION__ << "(): Invalid configuration! Not T1 or E1.";
|
|
LastError = error_msg.str();
|
|
delete p_drv_cfg_obj;
|
|
return 1;
|
|
}//switch(config.e1Ort1)
|
|
|
|
//FE_REFCLK(&sdla_fe_cfg) = 0; //optional
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//DAVIDR: for "TAPPING" set clock to WAN_NORMAL_CLK
|
|
//FE_CLK(&sdla_fe_cfg) = WAN_NORMAL_CLK;
|
|
//DAVIDR: for "PLAYBACK/RECORD" set clock to WAN_NORMAL_CLK or WAN_MASTER_CLK,
|
|
// depending on how the other side is configured!
|
|
|
|
if (config.Master) {
|
|
FE_CLK(&sdla_fe_cfg) = WAN_MASTER_CLK;
|
|
} else {
|
|
FE_CLK(&sdla_fe_cfg) = WAN_NORMAL_CLK;
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//DAVIDR: High Impedance can be used only with external filters installed!!
|
|
FE_HIMPEDANCE_MODE(&sdla_fe_cfg) = (config.HighImpedanceMode == true ? WANOPT_YES:WANOPT_NO);
|
|
FE_RX_SLEVEL(&sdla_fe_cfg) = config.MaxCableLoss;
|
|
FE_TXTRISTATE(&sdla_fe_cfg) = (config.TxTristateMode == true ? WANOPT_YES:WANOPT_NO);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//The same buffer settings will be used in both directions - Tx and Rx.
|
|
buffer_settings.buffer_multiplier_factor = ReceiveBufferSettings.BufferMultiplierFactor;
|
|
buffer_settings.number_of_buffers_per_api_interface = ReceiveBufferSettings.NumberOfBuffersPerPort;
|
|
|
|
return_code = p_drv_cfg_obj->set_t1_e1_configuration(&sdla_fe_cfg, &buffer_settings);
|
|
|
|
delete p_drv_cfg_obj;
|
|
return return_code;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::Open(const Configuration & config)
|
|
/// \brief Opens this port, setting its current configuration to the one provided
|
|
/// \author J. Markwordt
|
|
/// \date 10/05/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
bool SangomaPort::Open(const Configuration & config)
|
|
{
|
|
LastError = NO_ERROR_OCCURRED; // Reset so if the function is successful GetLastError() will return NO_ERROR_OCCURRED
|
|
|
|
EnterPortCriticalSection();
|
|
|
|
PORT_FUNC();
|
|
DBG_OPEN("%s(): CardNumber: %u, PortNumber: %u (mapped port: %u)\n", __FUNCTION__,
|
|
CardNumber, PortNumber, SangomaInterface->get_mapped_port_number());
|
|
|
|
DBG_PORT("%s, Framing: %u, lineCoding: %u, HighImpedanceMode: %u\n",
|
|
(config.e1Ort1 == T1 ? "T1" :
|
|
(config.e1Ort1 == E1 ? "E1" : "Error: Not T1 or E1")),
|
|
config.Framing,
|
|
config.lineCoding,
|
|
config.HighImpedanceMode);
|
|
|
|
// If the port is already opened, return false, it must be Closed first before it can be reopened
|
|
if (IsOpen) {
|
|
PORT_FUNC();
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::Open() failed to open, port " << GetPortNumber() << " is already opened.";
|
|
error_msg << "SangomaPort::Close() must be called before attempting to reopen.";
|
|
LastError = error_msg.str();
|
|
|
|
// Return false to indicate the open failed, but do not change
|
|
// IsOpen since port is currently open in a valid configuration
|
|
LeavePortCriticalSection();
|
|
return false;
|
|
}
|
|
|
|
// Apply configuration to the port after checking that the configuration is valid.
|
|
if(SetPortConfiguration(config)){
|
|
PORT_FUNC();
|
|
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::SetPortConfiguration() failed for port " << GetPortNumber() << ".";
|
|
LastError = error_msg.str();
|
|
|
|
Event.EventHandle = NULL;
|
|
ERR_PORT("SetPortConfiguration() failed! (CardNumber: %u, PortNumber: %u (mapped port: %u))\n",
|
|
CardNumber, PortNumber, SangomaInterface->get_mapped_port_number());
|
|
//axit(1);
|
|
LeavePortCriticalSection();
|
|
return false;
|
|
}
|
|
|
|
// Perform any operations necessary to open the port with the new configuration and prepare to receive data
|
|
if(SangomaInterface->init()){
|
|
PORT_FUNC();
|
|
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort: SangomaInterface->init() failed for port " << GetPortNumber() << ".";
|
|
LastError = error_msg.str();
|
|
|
|
Event.EventHandle = NULL;
|
|
ERR_PORT("SangomaInterface->init() failed! (CardNumber: %u, PortNumber: %u (mapped port: %u))\n",
|
|
CardNumber, PortNumber, SangomaInterface->get_mapped_port_number());
|
|
//exit(1);
|
|
LeavePortCriticalSection();
|
|
return false;
|
|
}
|
|
|
|
if(SangomaInterface->set_buffer_multiplier(&wp_api, ReceiveBufferSettings.BufferMultiplierFactor)){
|
|
PORT_FUNC();
|
|
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort: SangomaInterface->set_buffer_multiplier() failed for port " << GetPortNumber() << ".";
|
|
LastError = error_msg.str();
|
|
|
|
Event.EventHandle = NULL;
|
|
ERR_PORT("SangomaInterface->set_buffer_multiplier() failed! (CardNumber: %u, PortNumber: %u (mapped port: %u))\n",
|
|
CardNumber, PortNumber, SangomaInterface->get_mapped_port_number());
|
|
//exit(1);
|
|
LeavePortCriticalSection();
|
|
return false;
|
|
}
|
|
|
|
Event.EventHandle = SangomaInterface->get_wait_object_reference();
|
|
|
|
// Store the time that this successful Open() occurred, both for statistics
|
|
// purposes and so that we can calculate time elapsed since opening for
|
|
// determining whether we have acheived syncronization
|
|
time(&PortStatistics.TimeLastOpened);
|
|
|
|
DBG_PORT("%s(): PortStatistics.TimeLastOpened:%u (ptr: 0x%p)\n",
|
|
__FUNCTION__, (uint32_t)PortStatistics.TimeLastOpened, &PortStatistics.TimeLastOpened);
|
|
|
|
IsOpen = true;
|
|
|
|
PORT_FUNC();
|
|
// Save the current configuration since it was successfully applied to the port
|
|
CurrentConfiguration = config;
|
|
|
|
LeavePortCriticalSection();
|
|
// Unless the port was successfully opened, IsOpen will still be false
|
|
return IsOpen;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::Close()
|
|
/// \brief Closes this port
|
|
/// \return true if the port was successfully closed, false if
|
|
/// \author J. Markwordt
|
|
/// \date 10/05/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
bool SangomaPort::Close()
|
|
{
|
|
EnterPortCriticalSection();
|
|
PORT_FUNC();
|
|
|
|
LastError = NO_ERROR_OCCURRED; // Reset so if the function is successful GetLastError() will return NO_ERROR_OCCURRED
|
|
|
|
DBG_OPEN("%s(): CardNumber: %u, PortNumber: %u (mapped port: %u)\n", __FUNCTION__,
|
|
CardNumber, PortNumber, SangomaInterface->get_mapped_port_number());
|
|
|
|
// If the port is not currently opened just return true, there is nothing to do
|
|
if (!IsOpen) {
|
|
LeavePortCriticalSection();
|
|
return true; // this is not an error, there is just nothing to do, already closed
|
|
}
|
|
|
|
IsOpen = false;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Signal the wait object BEFORE deleting it so anyone who is waiting will not use it anymore
|
|
//sangoma_wait_obj_signal(SangomaInterface->get_wait_object_reference());
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Perform actions to close and cleanup the port
|
|
bool close_successful = false;
|
|
if(SangomaInterface->cleanup() == 0){
|
|
close_successful = true;
|
|
}else{
|
|
ERR_PORT("CardNumber: %u, PortNumber: %u (mapped port: %u): failed the cleanup()!!\n",
|
|
CardNumber, PortNumber, SangomaInterface->get_mapped_port_number());
|
|
}
|
|
|
|
if (close_successful) {
|
|
// Store the time that this successful Close() occurred for statistical purposes
|
|
time(&PortStatistics.TimeLastClosed);
|
|
LeavePortCriticalSection();
|
|
return true;
|
|
}
|
|
|
|
LeavePortCriticalSection();
|
|
return false;
|
|
}
|
|
|
|
bool SangomaPort::GetIsOpen()
|
|
{
|
|
bool boolTmpIsOpen;
|
|
|
|
if(TryEnterPortCriticalSection()){
|
|
//Do NOT wait! We only want to check, not actually wait for another thread to complete its work.
|
|
return false;
|
|
}
|
|
|
|
boolTmpIsOpen = IsOpen;
|
|
LeavePortCriticalSection();
|
|
|
|
return boolTmpIsOpen;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn efficient_32bit_byte_copy(unsigned char **p_destination_buf, unsigned char **p_source_buf, unsigned int num_bytes_to_copy){
|
|
/// \brief Copies data bytes from one byte buffer to another. This routine is optimized
|
|
/// for 32 bit processors. This routine does not handle detection of overrunning
|
|
/// the buffer boundaries. That responsibility is left to the calling routine.
|
|
///
|
|
/// \param **p_destination_buf : Address of a pointer to the destination byte buffer
|
|
/// \param **p_source_buf : Address of a pointer to the source byte buffer.
|
|
/// \param num_bytes_to_copy : Number of bytes to copy from the source buffer to the
|
|
/// destination buffer.
|
|
/// \author Andrew Park
|
|
/// \date 07/18/2005
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
const unsigned int BITMASK_FOR_LEAST_SIGNIFICANT_TWO_BITS = 0x3;
|
|
void efficient_32bit_byte_copy(unsigned char **p_destination_buf, unsigned char **p_source_buf, unsigned int num_bytes_to_copy){
|
|
// We do not need to do a NULL check here, because the function that calls this checks. NOTE: since this is a public
|
|
// function, there does still exist the possibility that NULL arrays may be passed in, but I didn't want to mess with
|
|
// the efficiency here if at all possible
|
|
|
|
//Transfer bytes in chunks of 32 bit words
|
|
int num_words = static_cast<int>(num_bytes_to_copy >> 2); //divide by 4 to get the integral # words
|
|
unsigned int *p_destination_buf_32bit = reinterpret_cast<unsigned int*>(*p_destination_buf);
|
|
unsigned int *p_source_buf_32bit = reinterpret_cast<unsigned int*>(*p_source_buf);
|
|
unsigned int i=0;
|
|
for(i=0;i<(unsigned int)num_words;i++){
|
|
*p_destination_buf_32bit++ = *p_source_buf_32bit++;
|
|
}
|
|
//Convert pointers back from 32 bit to byte pointers
|
|
*p_destination_buf = reinterpret_cast<unsigned char*>(p_destination_buf_32bit);
|
|
*p_source_buf = reinterpret_cast<unsigned char*>(p_source_buf_32bit);
|
|
|
|
//Transfer remaining bytes individually
|
|
unsigned int remaining_bytes = static_cast<unsigned int>(num_bytes_to_copy & BITMASK_FOR_LEAST_SIGNIFICANT_TWO_BITS);
|
|
for(i=0;i<remaining_bytes;i++) {
|
|
*(*p_destination_buf)++ = *(*p_source_buf)++;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::Read()
|
|
/// \brief Reads data and places the data in Port's ReceiveBuffer.
|
|
/// If ReceiveBuffer is not large enough to contain all of the data in the
|
|
/// Sangoma API receive buffer, an error ERROR_INVALID_DESTINATION_BUFFER_TOO_SMALL
|
|
// will be returned as this is a configuration error.
|
|
/// \return One of the following Status or Error codes:
|
|
/// LineDisconnected - Sangoma API inidcated Line Disconnect.
|
|
/// LineConnected - Sangoma API inidcated Line Connect.
|
|
/// ReadDataAvailable - Sangoma API inidcated there is receive buffer ready in API queue.
|
|
/// ERROR_NO_DATA_AVILABLE - lower level code reported no data available in host memory
|
|
/// ERROR_INVALID_DESTINATION_BUFFER - a NULL destination buffer was provided so nothing was read
|
|
/// ERROR_INVALID_DESTINATION_BUFFER_TOO_SMALL - a destination buffer was provided that
|
|
/// is too small to contain a full buffer's worth of data
|
|
/// ERROR_PORT_NOT_OPEN - Read attempted before the port had been opened
|
|
/// \author David Rokhvarg (davidr@sangoma.com)
|
|
/// \date 11/15/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
int SangomaPort::Read(unsigned int out_flags)
|
|
{
|
|
int return_code = ERROR_NO_DATA_AVILABLE;
|
|
|
|
EnterPortCriticalSection();
|
|
|
|
// The port must have been successfully opened with a valid configuration before a read can be performed
|
|
if (!IsOpen) {
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::Read(unsigned char*, int) attempted when port " << GetPortNumber() << " had not been opened yet.";
|
|
ERR_PORT("Port %u: SangomaPort::Read() attempted when port had not been opened yet!\n", GetPortNumber());
|
|
LastError = error_msg.str();
|
|
LeavePortCriticalSection();
|
|
return ERROR_PORT_NOT_OPEN;
|
|
}
|
|
|
|
switch(out_flags)//note that 'out_flags' is NOT treated as BitMap anymore - it is expected only a SINGLE bit to be set
|
|
{
|
|
case POLLIN:
|
|
if(SangomaInterface->read_data(&rxhdr, ReceiveBuffer->GetPortBuffer(), ReceiveBuffer->GetPortBufferSize()))
|
|
{
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: read_data() failed! Port: " << GetPortNumber() << " error description: DeviceIoControl() failed\n";
|
|
LastError = error_msg.str();
|
|
LeavePortCriticalSection();
|
|
return ERROR_DEVICE_IOCTL;
|
|
}
|
|
break;
|
|
case POLLPRI:
|
|
if(SangomaInterface->read_event(&wp_api))
|
|
{
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: read_event() failed! Port: " << GetPortNumber() << " error description: DeviceIoControl() failed\n";
|
|
LastError = error_msg.str();
|
|
LeavePortCriticalSection();
|
|
return ERROR_DEVICE_IOCTL;
|
|
}
|
|
break;
|
|
case POLLOUT:
|
|
return_code = TransmitBufferAvailable;
|
|
break;
|
|
default:
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::Read(unsigned int out_flags) for port " << GetPortNumber() << " invalid 'out_flags'=" << out_flags << "\n";
|
|
ERR_PORT("Port %u: SangomaPort::Read() invalid out_flags=0x%X!\n", GetPortNumber(), out_flags);
|
|
LastError = error_msg.str();
|
|
LeavePortCriticalSection();
|
|
return ERROR_INVALID_READ_REQUEST;
|
|
}//switch()
|
|
|
|
if (POLLIN == out_flags)
|
|
{
|
|
switch (rxhdr.operation_status)
|
|
{
|
|
case SANG_STATUS_RX_DATA_AVAILABLE:
|
|
return_code = ReadDataAvailable;
|
|
ReceiveBuffer->SetUserDataLength(rxhdr.data_length);
|
|
break;
|
|
default:
|
|
ERR_PORT("Port %u: Rx Error: Operation Status: %s (%d)\n", GetPortNumber(),
|
|
SDLA_DECODE_SANG_STATUS(rxhdr.operation_status), rxhdr.operation_status);
|
|
return_code = ERROR_NO_DATA_AVILABLE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (POLLPRI == out_flags)
|
|
{
|
|
wp_api_event_t *wp_tdm_api_event = &wp_api.wp_cmd.event;
|
|
|
|
switch (wp_api.wp_cmd.result)
|
|
{
|
|
case SANG_STATUS_SUCCESS:
|
|
|
|
switch(wp_tdm_api_event->wp_tdm_api_event_type)
|
|
{
|
|
case WP_TDMAPI_EVENT_LINK_STATUS:
|
|
if(wp_tdm_api_event->wp_tdm_api_event_link_status == WAN_EVENT_LINK_STATUS_CONNECTED){
|
|
return_code = LineConnected;
|
|
}else{
|
|
return_code = LineDisconnected;
|
|
}
|
|
break;
|
|
case WP_TDMAPI_EVENT_ALARM:
|
|
if(wp_tdm_api_event->wp_tdm_api_event_alarm == 0){
|
|
return_code = LineConnected;
|
|
}else{
|
|
return_code = LineDisconnected;
|
|
}
|
|
break;
|
|
default:
|
|
//FIXME: Remove this
|
|
ERR_PORT("Port %u INVALID EVENT Type 0x%X\n",GetPortNumber(),wp_tdm_api_event->wp_tdm_api_event_type);
|
|
exit(1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
if (rxhdr.operation_status == SANG_STATUS_RX_DATA_AVAILABLE) {
|
|
return_code = ReadDataAvailable;
|
|
} else {
|
|
ERR_PORT("Port %u: Event Error: Operation Status: %s (%d)\n", GetPortNumber(),
|
|
SDLA_DECODE_SANG_STATUS(rxhdr.operation_status), rxhdr.operation_status);
|
|
return_code = ERROR_NO_DATA_AVILABLE;
|
|
}
|
|
//FIXME: Remove this
|
|
ERR_PORT("Port %u INVALID EVENT\n",GetPortNumber());
|
|
exit(1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(return_code == ReadDataAvailable){
|
|
PortStatistics.BytesReceived += ReceiveBuffer->GetUserDataLength();
|
|
}
|
|
|
|
LeavePortCriticalSection();
|
|
return return_code;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::Write(unsigned char* p_source_buffer, const int bytes_to_write)
|
|
/// \brief Writes the specified number of bytes from the source buffer to the port
|
|
/// \param p_source_buffer Pointer to an array of unsigned chars used as the source of the
|
|
/// data to write. Assumes that it contains at least bytes_to_write
|
|
/// number of bytes.
|
|
/// \param bytes_to_write the number of bytes to write to the port
|
|
/// \return Zero if successful (all bytes are written) or one of the following error codes:
|
|
/// ERROR_NO_DATA_WRITTEN - no data was able to be written on the port
|
|
/// ERROR_INVALID_SOURCE_BUFFER - a NULL source buffer was provided so nothing was written
|
|
/// ERROR_PORT_NOT_OPEN - Write attempted before the port had been opened
|
|
/// \author J. Markwordt
|
|
/// \date 10/15/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
int SangomaPort::Write(unsigned char* p_source_buffer, const unsigned int bytes_to_write)
|
|
{
|
|
EnterPortCriticalSection();
|
|
//PORT_FUNC();
|
|
|
|
// The port must have been successfully opened with a valid configuration before a write can be performed
|
|
if (!IsOpen) {
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::Write(unsigned char*, int) attempted when port " << GetPortNumber() << " had not been opened yet.";
|
|
LastError = error_msg.str();
|
|
LeavePortCriticalSection();
|
|
return ERROR_PORT_NOT_OPEN;
|
|
}
|
|
|
|
// Check to make sure the source is valid before attempting to access it
|
|
bool invalid_source_buffer = (NULL == p_source_buffer);
|
|
if (invalid_source_buffer) {
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::Write(unsigned char*, int) attempted with invalid source buffer on port " << GetPortNumber() << ".";
|
|
LastError = error_msg.str();
|
|
LeavePortCriticalSection();
|
|
return ERROR_INVALID_SOURCE_BUFFER;
|
|
}
|
|
|
|
// Perform Sangoma API functions to write data to the port.
|
|
if(bytes_to_write > TransmitBuffer->GetPortBufferSize()){
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::Write(unsigned char*, int) attempted with Tx data length exceeding maximum " << GetPortNumber() << ".";
|
|
LastError = error_msg.str();
|
|
LeavePortCriticalSection();
|
|
return ERROR_INVALID_TX_DATA_LENGTH;
|
|
}
|
|
|
|
TransmitBuffer->SetUserDataLength(bytes_to_write);
|
|
//
|
|
//If src and dst buffers are the same, there is no need to copy the data because
|
|
//it is already there. This is the case for TxFile (see code in WriteChunkOfTxFile()).
|
|
//
|
|
if (TransmitBuffer->GetUserDataBuffer() != p_source_buffer) {
|
|
memcpy(TransmitBuffer->GetUserDataBuffer(), p_source_buffer, bytes_to_write);
|
|
}
|
|
|
|
int number_of_bytes_written = 0;
|
|
|
|
memset(&txhdr, 0x00, sizeof(txhdr));
|
|
|
|
#if 0
|
|
if (GetPortNumber() == 0) {
|
|
print_data_buffer((unsigned char*)TransmitBuffer->GetUserDataBuffer(), TransmitBuffer->GetUserDataLength());
|
|
}
|
|
#endif
|
|
|
|
if(SangomaInterface->transmit(&txhdr, TransmitBuffer->GetUserDataBuffer(), TransmitBuffer->GetUserDataLength())){
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::" << __FUNCTION__ << "() failed! Port: " << GetPortNumber() << " error description: DeviceIoControl() failed";
|
|
LastError = error_msg.str();
|
|
LeavePortCriticalSection();
|
|
return ERROR_DEVICE_IOCTL;
|
|
}
|
|
|
|
std::ostringstream error_msg;
|
|
|
|
switch(txhdr.operation_status)
|
|
{
|
|
case SANG_STATUS_SUCCESS:
|
|
PortStatistics.BytesSent += bytes_to_write;
|
|
number_of_bytes_written = bytes_to_write;
|
|
break;
|
|
case SANG_STATUS_TX_TIMEOUT:
|
|
error_msg << "ERROR: SangomaPort::" << __FUNCTION__ << "() failed! Port: " << GetPortNumber() << " error description: TX_TIMEOUT";
|
|
break;
|
|
case SANG_STATUS_TX_DATA_TOO_LONG:
|
|
error_msg << "ERROR: SangomaPort::" << __FUNCTION__ << "() failed! Port: " << GetPortNumber() << " error description: TX_DATA_TOO_LONG";
|
|
break;
|
|
case SANG_STATUS_TX_DATA_TOO_SHORT:
|
|
error_msg << "ERROR: SangomaPort::" << __FUNCTION__ << "() failed! Port: " << GetPortNumber() << " error description: TX_DATA_TOO_SHORT";
|
|
break;
|
|
case SANG_STATUS_LINE_DISCONNECTED:
|
|
error_msg << "ERROR: SangomaPort::" << __FUNCTION__ << "() failed! Port: " << GetPortNumber() << " error description: PORT_OUT_OF_SYNC";
|
|
break;
|
|
default:
|
|
break;
|
|
}//switch()
|
|
|
|
bool no_data_written = (0 == number_of_bytes_written);
|
|
if (no_data_written) {
|
|
LastError = error_msg.str();
|
|
LeavePortCriticalSection();
|
|
return ERROR_NO_DATA_WRITTEN;
|
|
}
|
|
|
|
LeavePortCriticalSection();
|
|
return 0;// ALL bytes were written
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetSynchronizationStatus()
|
|
/// \brief Closes this port
|
|
/// \return true if the port was successfully closed, false if
|
|
/// \author J. Markwordt
|
|
/// \date 10/05/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
SynchronizationStatus SangomaPort::GetSynchronizationStatus()
|
|
{
|
|
EnterPortCriticalSection();
|
|
PORT_FUNC();
|
|
|
|
// If the port is not currently open with a valid configuration
|
|
// the port cannot be in sync, simply return not in sync.
|
|
if (!IsOpen) {
|
|
PORT_FUNC();
|
|
LeavePortCriticalSection();
|
|
return PORT_NOT_IN_SYNC;
|
|
}
|
|
|
|
// Else we need to know if enough time has elapsed to be able to reliably
|
|
// check for alarms. If ALARM_WAIT_TIME_MS has not passed, the Sangoma card
|
|
// will always return no alarms, giving a false positive that we have found
|
|
// synchronization, when in fact we have not.
|
|
time_t CurrentTime;
|
|
time(&CurrentTime);
|
|
|
|
DBG_PORT("%s(): CurrentTime:%u, PortStatistics.TimeLastOpened:%u (ptr: 0x%p)\n",
|
|
__FUNCTION__, (uint32_t)CurrentTime, (uint32_t)PortStatistics.TimeLastOpened, &PortStatistics.TimeLastOpened);
|
|
|
|
#if 0
|
|
time_t t_time_diff = CurrentTime - PortStatistics.TimeLastOpened;
|
|
DBG_PORT("%s(): t_time_diff: %d\n", __FUNCTION__, t_time_diff);
|
|
//translate time differemce into milliseconds
|
|
t_time_diff *= 1000;
|
|
bool ready_to_check_for_alarms = (t_time_diff >= ALARM_WAIT_TIME_MS);
|
|
#else
|
|
double t_time_diff = difftime(CurrentTime, PortStatistics.TimeLastOpened);
|
|
DBG_PORT("%s(): t_time_diff: %f\n", __FUNCTION__, t_time_diff);
|
|
bool ready_to_check_for_alarms = (t_time_diff >= ALARM_WAIT_TIME_MS / 1000 / 2 /* allow to poll after 1/2 of maximum wait time (approximately 16 seconds) */);
|
|
#endif
|
|
|
|
DBG_PORT("%s(): ready_to_check_for_alarms: %d\n", __FUNCTION__, ready_to_check_for_alarms);
|
|
|
|
if (ready_to_check_for_alarms) {
|
|
// Check to see if there are alarms present. We aren't interested in
|
|
// what individual ports are present or saving them, just see if any
|
|
// are present.
|
|
char alarms_present = SangomaInterface->alarms_present();
|
|
if (alarms_present) {
|
|
sync_cnt=0;
|
|
if (t_time_diff >= ALARM_WAIT_TIME_MS / 1000) {
|
|
// Set the LastError string to indicate that
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::GetSynchronizationStatus() detected alarms present on port " << GetPortNumber() << " with the current configuration. Closing the port.";
|
|
LastError = error_msg.str();
|
|
|
|
LeavePortCriticalSection();
|
|
|
|
// DAVIDR: reached maximum wait time.
|
|
// The *caller* will decide what to do with the port: to close it or not.
|
|
return PORT_NOT_IN_SYNC;
|
|
} else {
|
|
// DAVIDR: the maximum wait time was not reached yet, keep waiting for sync.
|
|
LeavePortCriticalSection();
|
|
return PORT_WAITING_FOR_SYNC;
|
|
}
|
|
} else {
|
|
PortStatistics.TimeLastFoundSync = CurrentTime;
|
|
sync_cnt++;
|
|
LeavePortCriticalSection();
|
|
return PORT_IN_SYNC;
|
|
}
|
|
|
|
}else{
|
|
PORT_FUNC();
|
|
}
|
|
|
|
LeavePortCriticalSection();
|
|
return PORT_WAITING_FOR_SYNC;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetPortNumber() const
|
|
/// \brief Returns this port's number (zero indexed, relative to the card)
|
|
/// \return This port's number (zero indexed, relative to the card)
|
|
/// \author J. Markwordt
|
|
/// \date 10/15/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
unsigned int SangomaPort::GetPortNumber() const
|
|
{
|
|
return PortNumber;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetUnmappedPortNumber()
|
|
/// \brief Returns this port's number UNMAPPED (Without G3 port mapping). Use for debugging only.
|
|
/// \return This port's UNMAPPED number (zero indexed, relative to the card)
|
|
/// \author David Rokhvarg (davidr@sangoma.com)
|
|
/// \date 1/10/2008
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
unsigned int SangomaPort::GetUnmappedPortNumber()
|
|
{
|
|
unsigned int unmapped_port = 0;
|
|
EnterPortCriticalSection();
|
|
if(SangomaInterface != NULL){
|
|
unmapped_port = SangomaInterface->get_mapped_port_number();
|
|
}
|
|
LeavePortCriticalSection();
|
|
return unmapped_port;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetConfiguration() const
|
|
/// \brief Returns the current configuration of the port
|
|
/// \return Current Configuration structure for the port
|
|
/// \author J. Markwordt
|
|
/// \date 10/15/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
Configuration SangomaPort::GetConfiguration() const
|
|
{
|
|
PORT_FUNC();
|
|
return CurrentConfiguration;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetEvent() const
|
|
/// \brief Return the PortEvent associated with this port
|
|
/// \return PortEvent structure for events associated with this port
|
|
/// \author J. Markwordt
|
|
/// \date 10/18/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
PortEvent SangomaPort::GetEvent() const
|
|
{
|
|
return Event;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetDriverVersion() const
|
|
/// \brief Returns this port's hardware abstraction driver version number.
|
|
///
|
|
/// Sangoma has given the card a driver and the port what Sangoma refers to as a "Hardware
|
|
/// Abstraction Driver", and although these two should have the same version number if
|
|
/// installed properly, they are in fact two separate drivers.
|
|
///
|
|
/// This function is to retrieve the driver associated with the port's hardware abstraction
|
|
/// driver and can be used to verify that it matches the version number of the card as a whole.
|
|
/// \return DriverVersion containing the version of the software abstraction driver associated
|
|
/// with this port.
|
|
/// \author J. Markwordt
|
|
/// \date 10/17/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
DriverVersion SangomaPort::GetDriverVersion() /* DAVIDR: removed 'const' to get rid of compiler errors */
|
|
{
|
|
DriverVersion software_abstraction_driver_version;
|
|
wan_driver_version_t drv_version;
|
|
|
|
if(SangomaInterface->get_api_driver_version(&drv_version)){
|
|
std::ostringstream error_msg;
|
|
error_msg << "ERROR: SangomaPort::%s()" << __FUNCTION__ << " failed! Port: " << GetPortNumber();
|
|
LastError = error_msg.str();
|
|
}
|
|
|
|
//translate low level version structure into high level version structure
|
|
software_abstraction_driver_version.Major = drv_version.major;
|
|
software_abstraction_driver_version.Minor = drv_version.minor;
|
|
software_abstraction_driver_version.Build = drv_version.minor1;
|
|
software_abstraction_driver_version.Revision = drv_version.minor2;
|
|
|
|
return software_abstraction_driver_version;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetStatistics()
|
|
/// \brief Get the statistics for this port.
|
|
///
|
|
/// The reason this function is not declared constant is that the Statistics strucure
|
|
/// that is returned contains both statisics that are maintained in software by this
|
|
/// class, and statistics that are maintained in hardware on the port. We do not want
|
|
/// to continuously poll to keep these statistics up to date, so when requested, we will
|
|
/// issue low level commands to fill in these statistics.
|
|
/// \return Statistics structure containing information related to this port
|
|
/// \author J. Markwordt
|
|
/// \date 10/17/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
Statistics SangomaPort::GetStatistics()
|
|
{
|
|
/// Perform low level calls to retrieve the net_device_stats_t structure and update
|
|
/// PortStatistics with the statistics we are interested in. For example,
|
|
/// net_device_stats_t.rx_bytes maps to Statistics.BytesReceived. Statistics maintained
|
|
/// by the SangomaPort class (such as TimeLastOpened, TimeLastFoundSync, etc.) will be
|
|
/// returned as is.
|
|
wanpipe_chan_stats_t stats;
|
|
|
|
EnterPortCriticalSection();
|
|
if (IsOpen)
|
|
{
|
|
SangomaInterface->operational_stats(&stats);
|
|
//translate low level statistics structure into high level statistics structure
|
|
PortStatistics.BytesReceived = stats.rx_bytes;
|
|
PortStatistics.BytesSent = stats.tx_bytes;
|
|
PortStatistics.Errors = stats.errors;
|
|
}
|
|
LeavePortCriticalSection();
|
|
return PortStatistics;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::ClearStatistics()
|
|
/// \brief Clear the statistics for this port
|
|
/// \author J. Markwordt
|
|
/// \date 10/17/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
void SangomaPort::ClearStatistics()
|
|
{
|
|
/// \todo Reset the PortStatistics member to default values
|
|
|
|
/// Issue low level command to clear the statistics maintained on the port
|
|
EnterPortCriticalSection();
|
|
if (IsOpen)
|
|
{
|
|
SangomaInterface->flush_operational_stats();
|
|
}
|
|
LeavePortCriticalSection();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::FlushBuffers()
|
|
/// \brief Clear the statistics for this port
|
|
/// \author J. Markwordt
|
|
/// \date 10/17/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
void SangomaPort::FlushBuffers()
|
|
{
|
|
/// \todo Reset the PortStatistics member to default values
|
|
|
|
/// Issue low level command to clear the statistics maintained on the port
|
|
EnterPortCriticalSection();
|
|
if (IsOpen)
|
|
{
|
|
SangomaInterface->flush_buffers();
|
|
}
|
|
LeavePortCriticalSection();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetAlarms() const
|
|
/// \brief Retrieves the alarms from the hardware for this port
|
|
/// \return Alarms structure containing indications of the current alarms
|
|
/// \author J. Markwordt
|
|
/// \date 10/17/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
Alarms SangomaPort::GetAlarms()
|
|
{
|
|
Alarms alarms(FALSE);
|
|
unsigned long u_alarms = 1;
|
|
unsigned char adapter_type;
|
|
|
|
EnterPortCriticalSection();
|
|
if (IsOpen)
|
|
{
|
|
adapter_type = SangomaInterface->get_adapter_type();
|
|
SangomaInterface->read_te1_56k_stat(&u_alarms);
|
|
/// translate low level alarms structure into high level alarms structure
|
|
if (adapter_type == WAN_MEDIA_T1 || adapter_type == WAN_MEDIA_E1){
|
|
if(!strcmp(WAN_TE_LOS_ALARM(u_alarms), ON_STR)){
|
|
alarms.LossOfSignal = TRUE;
|
|
}
|
|
if(!strcmp(WAN_TE_ALOS_ALARM(u_alarms), ON_STR)){
|
|
alarms.AlternateLossOfSignalStatus = TRUE;
|
|
}
|
|
if(!strcmp(WAN_TE_RED_ALARM(u_alarms), ON_STR)){
|
|
alarms.Red = TRUE;
|
|
}
|
|
if(!strcmp(WAN_TE_AIS_ALARM(u_alarms), ON_STR)){
|
|
alarms.AlarmIndicationSignal = TRUE;
|
|
}
|
|
if(!strcmp(WAN_TE_OOF_ALARM(u_alarms), ON_STR)){
|
|
alarms.OutOfFrame = TRUE;
|
|
}
|
|
if (adapter_type == WAN_MEDIA_T1){
|
|
if(!strcmp(WAN_TE_YEL_ALARM(u_alarms), ON_STR)){
|
|
alarms.Yellow = TRUE;
|
|
}
|
|
}
|
|
|
|
if(!strcmp(WAN_TE_OOSMF_ALARM(u_alarms), ON_STR)){
|
|
alarms.LossOfSignalingMultiframe = TRUE;
|
|
}
|
|
if(!strcmp(WAN_TE_OOCMF_ALARM(u_alarms), ON_STR)){
|
|
alarms.LossOfCrcMultiframe = TRUE;
|
|
}
|
|
if(!strcmp(WAN_TE_OOOF_ALARM(u_alarms), ON_STR)){
|
|
alarms.OutOfOfflineFrame = TRUE;
|
|
}
|
|
if(!strcmp(WAN_TE_RAI_ALARM(u_alarms), ON_STR)){
|
|
alarms.ReceiveLossOfSignalV = TRUE;
|
|
}
|
|
}
|
|
}
|
|
LeavePortCriticalSection();
|
|
return alarms;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetLastError() const
|
|
/// \brief Returns a description of the last error that occurred
|
|
/// \return Returns a description of the last error that occurred (NO_ERROR_OCCURRED if the last command was successful)
|
|
/// \author J. Markwordt
|
|
/// \date 10/17/2007
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
std::string SangomaPort::GetLastError() const
|
|
{
|
|
return LastError;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetRxDataBuffer()
|
|
/// \brief Returns a pointer to received data.
|
|
/// \return Returns a pointer to received data after a successful Read()
|
|
/// \author David Rokhvarg (davidr@sangoma.com)
|
|
/// \date 1/10/2008
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
unsigned char *SangomaPort::GetRxDataBuffer()
|
|
{
|
|
return ReceiveBuffer->GetUserDataBuffer();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::GetRxDataLength()
|
|
/// \brief Returns length of received data.
|
|
/// \return Returns length of received data after a successful Read().
|
|
/// \author David Rokhvarg (davidr@sangoma.com)
|
|
/// \date 1/10/2008
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
unsigned int SangomaPort::GetRxDataLength()
|
|
{
|
|
return ReceiveBuffer->GetUserDataLength();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::EnterPortCriticalSection()
|
|
/// \brief Enter a SangomaPort operation in thread-safe manner.
|
|
/// \return No return value.
|
|
/// \author David Rokhvarg (davidr@sangoma.com)
|
|
/// \date 1/10/2008
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
void SangomaPort::EnterPortCriticalSection()
|
|
{
|
|
EnterCriticalSection(&cs_CriticalSection);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::LeavePortCriticalSection()
|
|
/// \brief Leave a SangomaPort operation in thread-safe manner.
|
|
/// \return No return value.
|
|
/// \author David Rokhvarg (davidr@sangoma.com)
|
|
/// \date 1/10/2008
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
void SangomaPort::LeavePortCriticalSection()
|
|
{
|
|
LeaveCriticalSection(&cs_CriticalSection);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::TryEnterPortCriticalSection()
|
|
/// \brief Try to enter a SangomaPort operation in thread-safe manner.
|
|
/// \return 1 - the mutex already taken, return without waiting 0 - the mutex was free
|
|
/// \author David Rokhvarg (davidr@sangoma.com)
|
|
/// \date 6/2/2010
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
int SangomaPort::TryEnterPortCriticalSection()
|
|
{
|
|
if (! TryEnterCriticalSection(&cs_CriticalSection) )
|
|
{
|
|
//If another thread already owns the critical section, the return value of TryEnterCriticalSection() is zero.
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int SangomaPort::SetAndOpenTxFile(char *szTxFileName)
|
|
{
|
|
pTxFile = fopen(szTxFileName, "rb" );
|
|
if( pTxFile == NULL){
|
|
ERR_PORT("Can't open file: [%s]\n", szTxFileName);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SangomaPort::WriteChunkOfTxFile()
|
|
{
|
|
unsigned char *user_tx_buffer = NULL;
|
|
|
|
if (!pTxFile) {
|
|
ERR_PORT("TxFile is NOT open!\n");
|
|
return 1;
|
|
}
|
|
|
|
user_tx_buffer = this->TransmitBuffer->GetUserDataBuffer();
|
|
|
|
//Initialize the buffer to 0xFF, so when End-of-File is reached,
|
|
//the padding up-to-end of tx buffer is automatic.
|
|
memset( user_tx_buffer, 0xFF, this->TransmitBuffer->GetUserDataLength() );
|
|
|
|
if (feof( pTxFile )) {
|
|
//End-of-File reached. Re-wind the file to zero.
|
|
fseek( pTxFile, 0, SEEK_SET );
|
|
}
|
|
|
|
//Read tx data from the file.
|
|
fread( user_tx_buffer, 1, TxMtu, pTxFile );
|
|
|
|
return this->Write(user_tx_buffer, TxMtu);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::LineLoopbackEnable()
|
|
/// \brief Enable line loopback for testing. All transmitted data will be also received
|
|
// locally. Requires the Port to be in Master clock mode.
|
|
/// \return 0 - success, non-zero - error
|
|
/// \author David Rokhvarg
|
|
/// \date 01/27/2011
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
int SangomaPort::LineLoopbackEnable()
|
|
{
|
|
int rc = SangomaInterface->loopback_command(WAN_TE1_DDLB_MODE, WAN_TE1_LB_ENABLE, ENABLE_ALL_CHANNELS);
|
|
|
|
if (rc) {
|
|
ERR_PORT("Port %u: %s() failed! rc: %d\n", GetPortNumber(), __FUNCTION__, rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// \fn SangomaPort::LineLoopbackDisable()
|
|
/// \brief Disable line loopback which was enabled by SangomaPort::LineLoopbackEnable()
|
|
/// \return 0 - success, non-zero - error
|
|
/// \author David Rokhvarg
|
|
/// \date 01/27/2011
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
int SangomaPort::LineLoopbackDisable()
|
|
{
|
|
int rc = SangomaInterface->loopback_command(WAN_TE1_DDLB_MODE, WAN_TE1_LB_DISABLE, ENABLE_ALL_CHANNELS);
|
|
|
|
if (rc) {
|
|
ERR_PORT("Port %u: %s() failed! rc: %d\n", GetPortNumber(), __FUNCTION__, rc);
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
#if defined(__WINDOWS__)
|
|
# ifndef _DEBUG
|
|
# pragma optimize("2gt",off)// Windows specific (MS_SPECIFIC), disables optimization in Release mode
|
|
# endif
|
|
#endif
|
|
|