Added basic analog circuit handling
git-svn-id: http://yate.null.ro/svn/yate/trunk@1422 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
86e684e44d
commit
c5bf148fbc
|
@ -56,6 +56,7 @@ class ZapDevice; // Zaptel I/O device. Implements the in
|
||||||
class ZapInterface; // D-channel signalling interface
|
class ZapInterface; // D-channel signalling interface
|
||||||
class ZapSpan; // Signalling span used to create voice circuits
|
class ZapSpan; // Signalling span used to create voice circuits
|
||||||
class ZapCircuit; // A voice circuit
|
class ZapCircuit; // A voice circuit
|
||||||
|
class ZapAnalogCircuit; // A analog circuit
|
||||||
class ZapSource; // Data source
|
class ZapSource; // Data source
|
||||||
class ZapConsumer; // Data consumer
|
class ZapConsumer; // Data consumer
|
||||||
|
|
||||||
|
@ -121,7 +122,7 @@ public:
|
||||||
None = ZT_EVENT_NONE,
|
None = ZT_EVENT_NONE,
|
||||||
OnHook = ZT_EVENT_ONHOOK,
|
OnHook = ZT_EVENT_ONHOOK,
|
||||||
OffHookRing = ZT_EVENT_RINGOFFHOOK,
|
OffHookRing = ZT_EVENT_RINGOFFHOOK,
|
||||||
Wink = ZT_EVENT_WINKFLASH,
|
WinkFlash = ZT_EVENT_WINKFLASH,
|
||||||
Alarm = ZT_EVENT_ALARM,
|
Alarm = ZT_EVENT_ALARM,
|
||||||
NoAlarm = ZT_EVENT_NOALARM,
|
NoAlarm = ZT_EVENT_NOALARM,
|
||||||
HdlcAbort = ZT_EVENT_ABORT,
|
HdlcAbort = ZT_EVENT_ABORT,
|
||||||
|
@ -144,6 +145,14 @@ public:
|
||||||
DTMFEvent = ZT_EVENT_PULSEDIGIT | ZT_EVENT_DTMFDOWN | ZT_EVENT_DTMFUP
|
DTMFEvent = ZT_EVENT_PULSEDIGIT | ZT_EVENT_DTMFDOWN | ZT_EVENT_DTMFUP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// List of hook to send events
|
||||||
|
enum HookEvent {
|
||||||
|
HookOn = ZT_ONHOOK,
|
||||||
|
HookOff = ZT_OFFHOOK,
|
||||||
|
HookWink = ZT_WINK,
|
||||||
|
HookFlash = ZT_FLASH
|
||||||
|
};
|
||||||
|
|
||||||
// List of valid IOCTL requests
|
// List of valid IOCTL requests
|
||||||
enum IoctlRequest {
|
enum IoctlRequest {
|
||||||
SetChannel = ZT_SPECIFY, // Specify a channel number for an opened device
|
SetChannel = ZT_SPECIFY, // Specify a channel number for an opened device
|
||||||
|
@ -175,6 +184,8 @@ public:
|
||||||
enum Type {
|
enum Type {
|
||||||
E1,
|
E1,
|
||||||
T1,
|
T1,
|
||||||
|
FXO,
|
||||||
|
FXS
|
||||||
};
|
};
|
||||||
|
|
||||||
ZapDevice(SignallingComponent* dbg, unsigned int chan, unsigned int circuit, bool interface);
|
ZapDevice(SignallingComponent* dbg, unsigned int chan, unsigned int circuit, bool interface);
|
||||||
|
@ -206,6 +217,10 @@ public:
|
||||||
// Update echo canceller
|
// Update echo canceller
|
||||||
// Set train to true on succesfully set echo canceller with non 0 echo taps
|
// Set train to true on succesfully set echo canceller with non 0 echo taps
|
||||||
bool setEchoTaps(unsigned int echoTaps, bool& train);
|
bool setEchoTaps(unsigned int echoTaps, bool& train);
|
||||||
|
// Send hook events
|
||||||
|
bool sendHook(HookEvent event, bool hookState);
|
||||||
|
// Send DTMFs events
|
||||||
|
bool sendDtmf(const char* tone);
|
||||||
// Start echo canceller training for a given period of time (in miliseconds)
|
// Start echo canceller training for a given period of time (in miliseconds)
|
||||||
bool startEchoTrain(unsigned int period);
|
bool startEchoTrain(unsigned int period);
|
||||||
// Get an event. Return 0 if no events. Set dtmf if the event is a DTMF
|
// Get an event. Return 0 if no events. Set dtmf if the event is a DTMF
|
||||||
|
@ -219,11 +234,11 @@ public:
|
||||||
int recv(void* buffer, int len);
|
int recv(void* buffer, int len);
|
||||||
// Send data. Return -1 on error or the number of bytes written
|
// Send data. Return -1 on error or the number of bytes written
|
||||||
int send(const void* buffer, int len);
|
int send(const void* buffer, int len);
|
||||||
// Make IOCTL requests on this device
|
|
||||||
bool ioctl(IoctlRequest request, void* param, int level = DebugWarn);
|
|
||||||
protected:
|
protected:
|
||||||
inline bool canRetry()
|
inline bool canRetry()
|
||||||
{ return errno == EAGAIN || errno == EINTR; }
|
{ return errno == EAGAIN || errno == EINTR; }
|
||||||
|
// Make IOCTL requests on this device
|
||||||
|
bool ioctl(IoctlRequest request, void* param, int level = DebugWarn);
|
||||||
private:
|
private:
|
||||||
SignallingComponent* m_owner; // Signalling component owning this device
|
SignallingComponent* m_owner; // Signalling component owning this device
|
||||||
bool m_interface; // True if this is a D-channel
|
bool m_interface; // True if this is a D-channel
|
||||||
|
@ -334,11 +349,14 @@ public:
|
||||||
virtual bool sendEvent(SignallingCircuitEvent::Type type, NamedList* params = 0);
|
virtual bool sendEvent(SignallingCircuitEvent::Type type, NamedList* params = 0);
|
||||||
// Consume data sent by the consumer
|
// Consume data sent by the consumer
|
||||||
void consume(const DataBlock& data);
|
void consume(const DataBlock& data);
|
||||||
private:
|
protected:
|
||||||
// Close device. Stop worker. Remove source consumer. Change status. Release memory if requested
|
// Close device. Stop worker. Remove source consumer. Change status. Release memory if requested
|
||||||
void cleanup(bool release, Status stat = Missing);
|
void cleanup(bool release, Status stat = Missing);
|
||||||
// Get and process events
|
// Get and process some events
|
||||||
void checkEvents();
|
void checkEvents();
|
||||||
|
// Process additional events. Return false if not processed
|
||||||
|
virtual bool processEvent(int event)
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
ZapDevice m_device; // The device
|
ZapDevice m_device; // The device
|
||||||
ZapDevice::Type m_type; // Circuit type
|
ZapDevice::Type m_type; // Circuit type
|
||||||
|
@ -361,6 +379,33 @@ private:
|
||||||
unsigned int m_consTotal; // Consumer. Total number of bytes transferred
|
unsigned int m_consTotal; // Consumer. Total number of bytes transferred
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// An analog circuit
|
||||||
|
class ZapAnalogCircuit : public ZapCircuit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline ZapAnalogCircuit(ZapDevice::Type type, unsigned int code, unsigned int channel,
|
||||||
|
ZapSpan* span, const NamedList& config, const NamedList& defaults,
|
||||||
|
const NamedList& params)
|
||||||
|
: ZapCircuit(type,code,channel,span,config,defaults,params),
|
||||||
|
m_hook(true)
|
||||||
|
{}
|
||||||
|
virtual ~ZapAnalogCircuit()
|
||||||
|
{}
|
||||||
|
// Get circuit data
|
||||||
|
virtual bool getParam(const String& param, String& value);
|
||||||
|
// Send an event
|
||||||
|
virtual bool sendEvent(SignallingCircuitEvent::Type type, NamedList* params = 0);
|
||||||
|
protected:
|
||||||
|
// Process additional events. Return false if not processed
|
||||||
|
virtual bool processEvent(int event);
|
||||||
|
// Receive hook events. Check device type and hook state
|
||||||
|
bool recvHook(int event);
|
||||||
|
// Change hook state if different
|
||||||
|
void changeHook(bool hook);
|
||||||
|
|
||||||
|
bool m_hook; // The hook status
|
||||||
|
};
|
||||||
|
|
||||||
// Data source
|
// Data source
|
||||||
class ZapSource : public DataSource
|
class ZapSource : public DataSource
|
||||||
{
|
{
|
||||||
|
@ -469,7 +514,7 @@ static TokenDict s_events[] = {
|
||||||
MAKE_NAME(None),
|
MAKE_NAME(None),
|
||||||
MAKE_NAME(OnHook),
|
MAKE_NAME(OnHook),
|
||||||
MAKE_NAME(OffHookRing),
|
MAKE_NAME(OffHookRing),
|
||||||
MAKE_NAME(Wink),
|
MAKE_NAME(WinkFlash),
|
||||||
MAKE_NAME(Alarm),
|
MAKE_NAME(Alarm),
|
||||||
MAKE_NAME(NoAlarm),
|
MAKE_NAME(NoAlarm),
|
||||||
MAKE_NAME(HdlcAbort),
|
MAKE_NAME(HdlcAbort),
|
||||||
|
@ -512,6 +557,8 @@ static TokenDict s_ioctl_request[] = {
|
||||||
static TokenDict s_types[] = {
|
static TokenDict s_types[] = {
|
||||||
MAKE_NAME(E1),
|
MAKE_NAME(E1),
|
||||||
MAKE_NAME(T1),
|
MAKE_NAME(T1),
|
||||||
|
MAKE_NAME(FXO),
|
||||||
|
MAKE_NAME(FXS),
|
||||||
{0,0}
|
{0,0}
|
||||||
};
|
};
|
||||||
#undef MAKE_NAME
|
#undef MAKE_NAME
|
||||||
|
@ -654,6 +701,54 @@ bool ZapDevice::setEchoTaps(unsigned int echoTaps, bool& train)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send hook events
|
||||||
|
bool ZapDevice::sendHook(HookEvent event, bool hookState)
|
||||||
|
{
|
||||||
|
int val = event;
|
||||||
|
switch (event) {
|
||||||
|
case HookOn:
|
||||||
|
case HookOff:
|
||||||
|
// Avoid sending duplicate hook state
|
||||||
|
if (hookState != (event == HookOn))
|
||||||
|
break;
|
||||||
|
DDebug(m_owner,DebugAll,"%sAlready %s hook [%p]",
|
||||||
|
m_name.safe(),hookState?"on":"off",this);
|
||||||
|
return false;
|
||||||
|
case HookWink:
|
||||||
|
case HookFlash:
|
||||||
|
// Avoid sending wink while hook is on or flash while hook is off
|
||||||
|
if (hookState == (event == HookWink))
|
||||||
|
break;
|
||||||
|
Debug(m_owner,DebugNote,"%sRequest to send hook %s while hook is %s [%p]",
|
||||||
|
m_name.safe(),event==HookWink?"wink":"flash",hookState?"on":"off",this);
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
XDebug(m_owner,DebugStub,"%sRequest to send unhandled hook event %u [%p]",
|
||||||
|
m_name.safe(),event,this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ioctl(SetHook,&val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send DTMFs events
|
||||||
|
bool ZapDevice::sendDtmf(const char* tone)
|
||||||
|
{
|
||||||
|
if (!(tone && *tone))
|
||||||
|
return false;
|
||||||
|
int len = strlen(tone);
|
||||||
|
if (len > ZT_MAX_DTMF_BUF - 2) {
|
||||||
|
Debug(m_owner,DebugNote,"%sCan't send dtmf '%s' (len %d > %u) [%p]",
|
||||||
|
m_name.safe(),tone,len,ZT_MAX_DTMF_BUF-2,this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DDebug(m_owner,DebugAll,"%sSending dtmf '%s' [%p]",m_name.safe(),tone,this);
|
||||||
|
ZT_DIAL_OPERATION dop;
|
||||||
|
dop.op = ZT_DIAL_OP_APPEND;
|
||||||
|
dop.dialstr[0] = 'T';
|
||||||
|
strncpy(dop.dialstr+1,tone,len);
|
||||||
|
return ioctl(ZapDevice::SetDial,&dop,DebugMild);
|
||||||
|
}
|
||||||
|
|
||||||
// Start echo training
|
// Start echo training
|
||||||
bool ZapDevice::startEchoTrain(unsigned int period)
|
bool ZapDevice::startEchoTrain(unsigned int period)
|
||||||
{
|
{
|
||||||
|
@ -1360,24 +1455,8 @@ bool ZapCircuit::process()
|
||||||
// Send an event through the circuit
|
// Send an event through the circuit
|
||||||
bool ZapCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params)
|
bool ZapCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params)
|
||||||
{
|
{
|
||||||
if (type == SignallingCircuitEvent::Dtmf) {
|
if (type == SignallingCircuitEvent::Dtmf)
|
||||||
const char* t = params ? params->getValue("tone") : 0;
|
return m_device.sendDtmf(params ? params->getValue("tone") : 0);
|
||||||
if (!(t && *t))
|
|
||||||
return false;
|
|
||||||
// Get the dial string operation
|
|
||||||
ZT_DIAL_OPERATION dop;
|
|
||||||
dop.op = ZT_DIAL_OP_APPEND;
|
|
||||||
int len = strlen(t);
|
|
||||||
if (len > ZT_MAX_DTMF_BUF - 1) {
|
|
||||||
DDebug(group(),DebugNote,
|
|
||||||
"ZapCircuit(%u). Can't send dtmf '%s' (len %d > %u) [%p]",
|
|
||||||
code(),t,len,ZT_MAX_DTMF_BUF-1,this);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DDebug(group(),DebugAll,"ZapCircuit(%u). Sending dtmf '%s' [%p]",code(),t,this);
|
|
||||||
strncpy(dop.dialstr,t,len);
|
|
||||||
return m_device.ioctl(ZapDevice::SetDial,&dop,DebugMild);
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug(group(),DebugNote,"ZapCircuit(%u). Unable to send event %u [%p]",
|
Debug(group(),DebugNote,"ZapCircuit(%u). Unable to send event %u [%p]",
|
||||||
code(),type,this);
|
code(),type,this);
|
||||||
|
@ -1489,6 +1568,8 @@ void ZapCircuit::checkEvents()
|
||||||
default:
|
default:
|
||||||
level = DebugStub;
|
level = DebugStub;
|
||||||
}
|
}
|
||||||
|
if (processEvent(event))
|
||||||
|
return;
|
||||||
SignallingCircuitEvent* e = CREATE_EVENT(SignallingCircuitEvent::Unknown);
|
SignallingCircuitEvent* e = CREATE_EVENT(SignallingCircuitEvent::Unknown);
|
||||||
addEvent(e);
|
addEvent(e);
|
||||||
DDebug(group(),level,"ZapCircuit(%u). Got event %d ('%s') [%p]",
|
DDebug(group(),level,"ZapCircuit(%u). Got event %d ('%s') [%p]",
|
||||||
|
@ -1496,6 +1577,143 @@ void ZapCircuit::checkEvents()
|
||||||
#undef CREATE_EVENT
|
#undef CREATE_EVENT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZapAnalogCircuit
|
||||||
|
*/
|
||||||
|
// Get circuit data
|
||||||
|
bool ZapAnalogCircuit::getParam(const String& param, String& value)
|
||||||
|
{
|
||||||
|
if (param == "hook") {
|
||||||
|
value = String::boolText(m_hook);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return ZapCircuit::getParam(param,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send an event
|
||||||
|
bool ZapAnalogCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case SignallingCircuitEvent::Dtmf:
|
||||||
|
return ZapCircuit::sendEvent(type,params);
|
||||||
|
case SignallingCircuitEvent::OnHook:
|
||||||
|
case SignallingCircuitEvent::OffHook:
|
||||||
|
case SignallingCircuitEvent::Wink:
|
||||||
|
case SignallingCircuitEvent::Flash:
|
||||||
|
if (m_type != ZapDevice::FXS) {
|
||||||
|
Debug(group(),DebugNote,
|
||||||
|
"ZapCircuit(%u). Request to send hook event %u on %s device [%p]",
|
||||||
|
code(),type,lookup(m_type,s_types),this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case SignallingCircuitEvent::OnHook:
|
||||||
|
if (!m_device.sendHook(ZapDevice::HookOn,m_hook))
|
||||||
|
return false;
|
||||||
|
changeHook(true);
|
||||||
|
return true;
|
||||||
|
case SignallingCircuitEvent::OffHook:
|
||||||
|
if (!m_device.sendHook(ZapDevice::HookOff,m_hook))
|
||||||
|
return false;
|
||||||
|
changeHook(false);
|
||||||
|
return true;
|
||||||
|
case SignallingCircuitEvent::Wink:
|
||||||
|
return m_device.sendHook(ZapDevice::HookWink,m_hook);
|
||||||
|
case SignallingCircuitEvent::Flash:
|
||||||
|
return m_device.sendHook(ZapDevice::HookFlash,m_hook);
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return ZapCircuit::sendEvent(type,params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process additional events. Return false if not processed
|
||||||
|
bool ZapAnalogCircuit::processEvent(int event)
|
||||||
|
{
|
||||||
|
#define CREATE_EVENT(sce) new SignallingCircuitEvent(sce,lookup(event,s_events))
|
||||||
|
switch (event) {
|
||||||
|
#if 0
|
||||||
|
// Unhandled
|
||||||
|
DialComplete
|
||||||
|
RingerOn
|
||||||
|
RingerOff
|
||||||
|
HookChanged
|
||||||
|
BitsChanged
|
||||||
|
PulseStart
|
||||||
|
Timeout
|
||||||
|
TimerPing
|
||||||
|
RingBegin
|
||||||
|
Polarity
|
||||||
|
#endif
|
||||||
|
case ZapDevice::OnHook:
|
||||||
|
if (!recvHook(event))
|
||||||
|
break;
|
||||||
|
changeHook(true);
|
||||||
|
addEvent(CREATE_EVENT(SignallingCircuitEvent::OnHook));
|
||||||
|
break;
|
||||||
|
case ZapDevice::OffHookRing:
|
||||||
|
if (!recvHook(event))
|
||||||
|
break;
|
||||||
|
changeHook(false);
|
||||||
|
addEvent(CREATE_EVENT(SignallingCircuitEvent::OffHook));
|
||||||
|
break;
|
||||||
|
case ZapDevice::WinkFlash:
|
||||||
|
if (!recvHook(event))
|
||||||
|
break;
|
||||||
|
if (m_hook)
|
||||||
|
addEvent(CREATE_EVENT(SignallingCircuitEvent::Flash));
|
||||||
|
else
|
||||||
|
addEvent(CREATE_EVENT(SignallingCircuitEvent::Wink));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#undef CREATE_EVENT
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Received hook events. Check device type and hook state
|
||||||
|
bool ZapAnalogCircuit::recvHook(int event)
|
||||||
|
{
|
||||||
|
if (m_type != ZapDevice::FXO) {
|
||||||
|
Debug(group(),DebugNote,
|
||||||
|
"ZapCircuit(%u). Received hook event '%s' on %s device [%p]",
|
||||||
|
code(),lookup(event,s_events),lookup(m_type,s_types),this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case ZapDevice::OnHook:
|
||||||
|
if (m_hook)
|
||||||
|
break;
|
||||||
|
return true;
|
||||||
|
case ZapDevice::OffHookRing:
|
||||||
|
if (!m_hook)
|
||||||
|
break;
|
||||||
|
return true;
|
||||||
|
case ZapDevice::WinkFlash:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DDebug(group(),DebugMild,"ZapCircuit(%u). Received '%s' while %s hook [%p]",
|
||||||
|
code(),lookup(event,s_events),m_hook?"on":"off",this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change hook state if different
|
||||||
|
void ZapAnalogCircuit::changeHook(bool hook)
|
||||||
|
{
|
||||||
|
if (m_hook == hook)
|
||||||
|
return;
|
||||||
|
DDebug(group(),DebugInfo,"ZapCircuit(%u). Hook changed to %s [%p]",
|
||||||
|
code(),hook?"on":"off",this);
|
||||||
|
m_hook = hook;
|
||||||
|
}
|
||||||
|
|
||||||
}; // anonymous namespace
|
}; // anonymous namespace
|
||||||
|
|
||||||
#endif /* _WINDOWS */
|
#endif /* _WINDOWS */
|
||||||
|
|
Loading…
Reference in New Issue