/*****************************************************************************
* OpenTel Telephony Server & Framework
* Copyright (c) 1995-99 OpenComm do Brasil Ltda.
* Todos os direitos reservados.
* Este arquivo contem material confidencial de OpenComm do Brasil, e deve
* darse tratamento como tal.
******************************************************************************/
#ident "@(#) $Header: /cvsroot/opentel/opentel/server/drivers/dialogic/otdialgc.cpp,v 1.2 2000/03/24 05:16:43 jbernab Exp $"
#include <otconfig.h>
#ifdef _WINDOWS
#include <windows.h>
#include <io.h>
#endif
#ifdef CONFIG_DIALOGIC_GC
extern "C" {
#include <srllib.h>
#include <dtilib.h>
#include <dxxxlib.h>
#include <gclib.h>
#include <gcerr.h>
};
#include <otpstnint.includes>
#include <dialogic/otdialogic.h>
#include <otarchive.includes>
#include <otbus.includes> // Bus Stuff
#include <dialogic/otdialsc.h>
#include <otgroup.includes>
#include <otgroupim.includes>
OtDialogicGc::OtDialogicGc(const OtString &dev,OtCCDir dir, OtBus *bus) :
OtPSTNInterface(dir),
_linedev(0),
_devName(dev),
_call(NULL),
_st(Blocked),
m_bus(bus)
{
setName("OtDialogicGc(" + _devName + ")" );
open();
}
OtDialogicGc::~OtDialogicGc(void)
{
close();
}
OtTimeSlotListener *OtDialogicGc::getListener()
{
return m_dti->getListener();
}
OtTimeSlotTransmitter *OtDialogicGc::getTransmitter()
{
return m_dti->getTransmitter();
}
int OtDialogicGc::open(void)
{
static int inited=0;
int ret;
if(!inited) { // This executes the first time some one opens a gc device
inited=1;
if(gc_Start(NULL)<0)
throw OtDialogicGcException();
}
if((ret=gc_Open(&_linedev,_devName,NULL))<0) {
OtWarning("Error: gc_Open dev:%s\n",(char *)_devName);
throw OtDialogicGcException(this);
}
gc_SetUsrAttr(_linedev, (void *) this);
m_dti=new OtDialogicDti(this);
return ret;
}
int OtDialogicGc::close(void)
{
int ret=0;
if(_linedev) {
if((ret=gc_Close(_linedev))<0)
throw OtDialogicGcException(this);
_linedev=0;
}
if(m_dti)
delete m_dti;
return ret;
}
void OtDialogicGc::attachToDxx()
{
if(this->getGroup()==NULL)
return; // Cannot attach yet, resource is not part of any group
OT_ASSERT_KINDOF(OtGroupImpl,this->getGroup());
OtGroupImpl *gr=(OtGroupImpl*) this->getGroup();
if(gr) {
OtToneGenerator *tg=gr->getToneGenerator();
if(tg->isKindOf(OT_RUNTIME_CLASS(OtDialogicToneGenerator))) {
gc_Attach(_linedev,((OtDialogicToneGenerator*)tg)->getDxx()->getFd(),EV_SYNC);
}
}
}
void OtDialogicGc::detachFromDxx()
{
if(this->getGroup()==NULL)
return; // Resource is not part of any group
OT_ASSERT_KINDOF(OtGroupImpl,this->getGroup());
OtGroupImpl *gr=(OtGroupImpl*) this->getGroup();
if(gr) {
OtToneGenerator *tg=gr->getToneGenerator();
if(tg->isKindOf(OT_RUNTIME_CLASS(OtDialogicToneGenerator))) {
gc_Detach(_linedev,((OtDialogicToneGenerator*)tg)->getDxx()->getFd(),EV_SYNC);
}
}
}
int OtDialogicGc::waitCall(void)
{
attachToDxx(); // TODO: Added by JEB 31/4/99 to test
if(gc_WaitCall(_linedev,NULL,NULL,0,EV_ASYNC)<0)
throw OtDialogicGcException(this);
}
int OtDialogicGc::answerCall(void)
{
if(_call)
_call->answerCall();
return 0;
}
int OtDialogicGc::releaseCall(void)
{
if(_call) {
delete _call;
_call=NULL;
}
return 0;
}
#if 0
long OtDialogicGc::getNonIdleTime() const
{
return (::time(NULL)-_connTs);
}
#endif
OtCall *OtDialogicGc::getCall() const
{
return _call;
}
OtCall *OtDialogicGc::makeCallSelf(const OtString &phone)
{
CRN crn;
if(gc_MakeCall(_linedev,&crn,(char *)phone,NULL,0,EV_ASYNC)<0)
throw OtDialogicGcException(this);
OtDebug(OT_DEBUG_GC,"%s:%d crn=%08x\n",__PRETTY_FUNCTION__,__LINE__,crn);
_call=new OtDialogicGcCall(this,OtCall::Outbound,crn);
return _call;
}
OtCall *OtDialogicGc::makeCall(const OtString &phone)
{
// First implement any framework functionality
if(phone.isEmpty()) // Check phone is dialable TODO
// throw OtPSTNInterfaceException(this,"Cannot MakeCall: Phone is invalid");
throw OtException("Cannot MakeCall: Phone is invalid");
if(getDir()!=Outbound) // Check direction is Outbound
// throw OtPSTNInterfaceException(this,"I can only MakeCall in an outbound channel");
throw OtException("I can only MakeCall in an outbound channel");
makeCallSelf(phone);
return _call;
}
void OtDialogicGc::setCallingNumber(const OtString &phone)
{
if(gc_SetCallingNum(_linedev,(char *)phone)<0)
throw OtDialogicGcException(this);
}
int OtDialogicGc::inboundOnEvent(OtDialogicGcEvent *e)
{
CRN crn=e->getCRN();
switch(e->getType()) {
case GCEV_DROPCALL:
attachToDxx();
break;
case GCEV_DISCONNECTED:
_connTs=0;
_lastTs=::time(NULL);
break;
case GCEV_OFFERED:
_connTs=::time(NULL);
_call=new OtDialogicGcCall(this,OtCall::Inbound,crn);
dispatchEvent(OtPSTNInterfaceEvent::eventOffered);
break;
case GCEV_ANSWERED:
case GCEV_CONNECTED:
detachFromDxx();
break;
case GCEV_BLOCKED:
detachFromDxx();
_st=Blocked;
_blockTs=::time(NULL);
dispatchEvent(OtPSTNInterfaceEvent::eventBlocked);
break;
case GCEV_UNBLOCKED:
attachToDxx();
_st=Unblocked;
dispatchEvent(OtPSTNInterfaceEvent::eventUnblocked);
break;
case GCEV_RESETLINEDEV:
break;
}
}
int OtDialogicGc::outboundOnEvent(OtDialogicGcEvent *e)
{
CRN crn=e->getCRN();
switch(e->getType()) {
case GCEV_DROPCALL:
attachToDxx();
break;
case GCEV_DISCONNECTED:
_connTs=0;
_lastTs=::time(NULL);
break;
case GCEV_OFFERED:
_connTs=::time(NULL);
_call=new OtDialogicGcCall(this,OtCall::Inbound,crn);
dispatchEvent(OtPSTNInterfaceEvent::eventOffered);
break;
case GCEV_ANSWERED:
case GCEV_CONNECTED:
detachFromDxx();
break;
case GCEV_BLOCKED:
detachFromDxx();
_st=Blocked;
_blockTs=::time(NULL);
dispatchEvent(OtPSTNInterfaceEvent::eventBlocked);
break;
case GCEV_UNBLOCKED:
attachToDxx();
_st=Unblocked;
dispatchEvent(OtPSTNInterfaceEvent::eventUnblocked);
break;
case GCEV_RESETLINEDEV:
break;
}
}
int OtDialogicGc::onMessage(OtMessage *msg)
{
OtEvent *e=((OtDlgMsg *)msg)->getEv();
if(e->getClass()==OtDialogicGcEvent::eventClass) {
switch(getDir()) {
case Inbound:
inboundOnEvent((OtDialogicGcEvent *)e);
break;
case Outbound:
outboundOnEvent((OtDialogicGcEvent *)e);
break;
case Both:
throw OtException("Bidirectional channel not supported in GlobalCall OtDialogicGc");
break;
}
}
OtDlgMsg m(e);
OtMessageSource::dispatchMessage(&m);
}
void OtDialogicGc::dispatchEvent(OtEventType t)
{
OtPSTNInterfaceEvent ev(*this,t);
postEvent(ev);
}
int OtDialogicGc::isForMe(OtDialogicEvent *e)
{
return (e->getDev()==_linedev); //
}
void OtDialogicGc::dump(OtString &context) const
{
char tmp[512];
OtString callStr("NULL");
if(_call)
_call->dump(callStr);
context += OtString::Format(
"OtDialogicGc(%08x) {\n\t_linedev=%d, _devName=%s, _st=%d,\n\t_connTs=%d, _lastTs=%d, _blockTs=%d,\n\t_call=%s \n}",
this, _linedev, (char *)_devName, _st, _connTs, _lastTs, _blockTs, (char *)callStr);
}
//
//
// OtDialogicGcCall
//
//
OtDialogicGcCall::OtDialogicGcCall(OtDialogicGc *gc,OtCallDir dir, CRN c) :
OtCall(gc,dir),
_gc(gc),
_crn(c)
{
_gc->OtMessageSource::addTarget((OtMessageTarget *)this);
}
OtDialogicGcCall::~OtDialogicGcCall(void)
{
_gc->OtMessageSource::removeTarget(this);
_gc=NULL;
}
OtDialogicGcCall::inboundOnEvent(OtDialogicGcEvent *e)
{
switch(e->getType()) {
case GCEV_DROPCALL:
_becoTs=::time(NULL);
dispatchEvent(OtCallEvent::eventDropCall);
gc_ReleaseCall(_crn);
_crn=0;
break;
case GCEV_DISCONNECTED:
_becoTs=::time(NULL);
dispatchEvent(OtCallEvent::eventDisconnected);
break;
case GCEV_OFFERED:
_becoTs=::time(NULL);
// dispatchEvent(OtCallEvent::eventOffered); // This is sent by the Call Channel Resource
break;
case GCEV_ANSWERED:
setState1(Avail);
dispatchEvent(OtCallEvent::eventAnswered);
break;
case GCEV_CONNECTED:
// We dont have access to getAni and getDNIS
setState1(Avail);
_connTs=::time(NULL);
setState1(Avail);
dispatchEvent(OtCallEvent::eventConnected);
break;
case GCEV_ALERTING:
dispatchEvent(OtCallEvent::eventAlerting);
break;
break;
}
}
OtDialogicGcCall::outboundOnEvent(OtDialogicGcEvent *e)
{
switch(e->getType()) {
case GCEV_DROPCALL:
_becoTs=::time(NULL);
dispatchEvent(OtCallEvent::eventDropCall);
gc_ReleaseCall(_crn);
_crn=0;
break;
case GCEV_DISCONNECTED:
_becoTs=::time(NULL);
dispatchEvent(OtCallEvent::eventDisconnected);
break;
case GCEV_OFFERED:
_becoTs=::time(NULL);
break;
case GCEV_ANSWERED:
setState1(Avail);
dispatchEvent(OtCallEvent::eventAnswered);
break;
case GCEV_CONNECTED:
// We dont have access to getAni and getDNIS
setState1(Avail);
_connTs=::time(NULL);
setState1(Avail);
dispatchEvent(OtCallEvent::eventConnected);
break;
case GCEV_ALERTING:
dispatchEvent(OtCallEvent::eventAlerting);
break;
}
}
OtDialogicGcCall::onMessage(OtMessage *msg)
{
OtEvent *_e=((OtDlgMsg *)msg)->getEv();
if(_e->getClass()==OtDialogicGcEvent::eventClass) {
OtDialogicGcEvent *e=(OtDialogicGcEvent *)_e;
if(e->getCRN()==_crn) { // Is this event mine?
switch(getDir()) {
case Inbound:
inboundOnEvent(e);
break;
case Outbound:
outboundOnEvent(e);
break;
}
}
}
}
void OtDialogicGcCall::dispatchEvent(OtEventType t)
{
OtCallEvent ev(this->getId(),this,t);
postEvent(ev);
}
int OtDialogicGcCall::answerCall(void)
{
OT_TRACE(OT_DEBUG_GC);
setState1(AnsweringCall);
if(gc_AnswerCall(_crn, 0, EV_ASYNC)<0) // 0 is rings!!
throw OtDialogicGcException(_gc);
}
int OtDialogicGcCall::dropCall(void) //DropCause dp)
{
OT_TRACE(OT_DEBUG_GC);
if(gc_DropCall(_crn, GC_NORMAL_CLEARING, EV_ASYNC)<0)
throw OtDialogicGcException(_gc);
}
OtString OtDialogicGcCall::getAni(void)
{
if(_crn && !( getState()==Null || getState()==Idle || getState()==Disconnected || getState()==Alerting )) {
if(gc_GetANI(_crn,_ani)<0)
throw OtDialogicGcException(_gc);
}
return _ani;
}
OtString OtDialogicGcCall::getDnis(void)
{
if(_crn && !( getState()==Null || getState()==Idle || getState()==Disconnected || getState()==Alerting )) {
if(gc_GetDNIS(_crn,_dnis)<0)
throw OtDialogicGcException(_gc);
}
return _dnis;
}
OtCall::OtCallState OtDialogicGcCall::getState(void) const
{
int cs=GCST_NULL; // this is when _crn == 0
if(_crn)
if(gc_GetCallState(_crn, &cs)<0)
throw OtDialogicGcException(_gc);
switch(cs) {
case GCST_NULL:
_st=Null;
break;
case GCST_ACCEPTED:
_st=Accepted;
break;
case GCST_ALERTING:
_st=Alerting;
break;
case GCST_CONNECTED:
_st=Connected;
break;
case GCST_OFFERED:
_st=Offered;
break;
case GCST_DIALING:
_st=Dialing;
break;
case GCST_IDLE:
_st=Idle;
break;
case GCST_DISCONNECTED:
_st=Disconnected;
break;
default:
throw OtException("OtDialogcGcCall::getState(): Invalid State");
break;
}
return OtCall::getState(); // Base class getState
}
OtDialogicGcCall::OtGcState1 OtDialogicGcCall::getState1(void) const
{
return _gcst1;
}
OtDialogicGcCall::OtGcState1 OtDialogicGcCall::setState1(OtGcState1 s)
{
_gcst1=s;
}
void OtDialogicGcCall::dump(OtString &context) const
{
context +=OtString::Format(
"OtDialogicGcCall(%08x) {\n\t_gc=%08x, _crn=%08x, _gcst1=%d,\n\t_ani=%s, _dnis=%s, _becoTs=%d, _connTs=%d, _discTs=%d\n}",
this, _gc, _crn, _gcst1, (char *)_ani, (char *)_dnis, _becoTs, _connTs, _discTs);
}
//
//
// OtDialogicGcEvent
//
//
OT_IMPLEMENT_SERIAL(OtDialogicGcEvent,OtDialogicEvent,0);
OtDialogicGcEvent::OtDialogicGcEvent(void) :
OtDialogicEvent(this->getId(),eventClass)
{
gc_GetMetaEvent(&_me);
gc_GetCRN(&_crn,&_me);
}
OtDialogicGcEvent::~OtDialogicGcEvent(void)
{
_crn=0;
}
//
//
// OtDialogicGcException
//
//
OtDialogicGcException::OtDialogicGcException(void) :
_gc(NULL)
{
m_err=makeErrorString();
};
OtDialogicGcException::OtDialogicGcException(const OtDialogicGc *gc) :
_gc(gc)
{
m_err=makeErrorString();
};
OtString OtDialogicGcException::makeErrorString(void)
{
OtString strbuf;
if(gc_ErrorValue(&_gc_error,&_cclibid,&_cc_error)==GC_SUCCESS) {
gc_ResultMsg(LIBID_GC, (long) _gc_error, &_gc_msg);
gc_ResultMsg(_cclibid, _cc_error, &_lib_msg);
gc_CCLibIDToName(_cclibid, &_lib_name);
strbuf = OtString::Format("GlobalCall error 0x%lx - %s\n%s library error 0x%lx - %s\n",_gc_error,_gc_msg,_lib_name,_cc_error,_lib_msg);
}
else
strbuf = "Could not get GlobalCall error\n";
OtString tmp;
if(_gc)
_gc->dump(tmp);
return strbuf + tmp;
}
//
//
// This is needed by the Dialogic Global Call Library
//
//
extern "C" void is_Start( void )
{
}
#endif