www.pudn.com > d4j.zip > R2CASChannel.java
// local.dialogic.R2CASChannel
// $Id: R2CASChannel.java,v 1.15 2003/11/13 11:51:47 cgm8 Exp $
/*
* Copyright (c) 1999 Carlos G Mendioroz.
*
* This file is part of D4J.
*
* D4J is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* D4J is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Report problems and direct all questions to:
*
* tron@acm.org
*/
package local.dialogic;
public class R2CASChannel extends Channel implements Runnable {
// Constantes
private static final int INIT = -1;
private static final int RESET = 0;
private static final int IDLE = 1;
private static final int RSEIZED = 2;
private static final int ICALL = 3;
private static final int RINGS = 4;
private static final int IN = 5;
private static final int OFFH = 6;
private static final int DIAL = 7;
private static final int DIALOK = 8;
private static final int OUT = 9;
private static final int ERROR = 10;
// Handy constants
private static final int A = Dialogic.DTB_ABIT;
private static final int B = Dialogic.DTB_BBIT;
private static final int C = Dialogic.DTB_CBIT;
private static final int D = Dialogic.DTB_DBIT;
private static final int CA = Dialogic.DTC_ABIT;
private static final int CB = Dialogic.DTC_BBIT;
private static final int CC = Dialogic.DTC_CBIT;
private static final int CD = Dialogic.DTC_DBIT;
private static final int WINK = Dialogic.DTMM_WINK;
// Protocol constants
private static final int R2Idle = 200; // Lapse in IDLE
private static final int R2InterDigit = 15000;// timeout
private static final int R2OHDelay = 1000; // Wait for seizure conf
private static final int R2SimSeizureDelay = 200; // Keep signaled
private static final int R2ImpulseGuard = 300;// Do not pay att. to fsig
private static final int R2ConnDelayOut = 60; // Delay before connection
private static final int R2ConnDelayIn = 75; // Delay before connection
// reject reasons
public static final int CONGESTION = 0;
public static final int BUSY = 1;
public static final int BADNUMBER = 2;
public static final int NOTINSERVICE = 3;
// Variables
Voice voiceDev = null;
DTI dtiDev = null;
boolean ra = false, rb = false;
boolean xa = false, xb = false;
private int linestate = -1;
private int pulses = 0;
private String ani = null;
private int r2tone = 0;
private int ringsSent = 0;
private boolean ringPhase = true;
private int inDnisLength = 4;
private String dnisPref = "";
private boolean freeAccept = false;
private boolean A3B6Accept = false;
public R2CASChannel(String dtiName, String voiceName) {
this (dtiName, voiceName, "");
}
public R2CASChannel(String dtiName, String voiceName, String dnisPreffix) {
super();
dtiDev = new DTI(this, dtiName);
voiceDev = new Voice(this, voiceName);
// link
dtiDev.listen(voiceDev);
voiceDev.listen(dtiDev);
//
linestate = INIT;
dnisPref = dnisPreffix;
ra = dtiDev.getA();
rb = dtiDev.getB();
dtiDev.setsig(xa = true, xb = true);
voiceDev.r2_creasig();
group = new ThreadGroup(dtiName + "/" + voiceName + " group");
serviceThread = new Thread(group, this, dtiName + "/" + voiceName + " service");
serviceThread.start();
}
public void close()
{
super.clear();
if (serviceThread != null) {
Channel.stopGroup(this);
serviceThread.interrupt();
try {
serviceThread.join(500);
}
catch (InterruptedException ie) {};
serviceThread = null;
}
if (dtiDev != null) {
dtiDev.close();
dtiDev = null;
}
if (voiceDev != null) {
voiceDev.close();
voiceDev = null;
}
}
public Voice getVoice() {
return voiceDev;
}
public Device getNetwork() {
return dtiDev;
}
public void run() {
int dnisl;
StringBuffer dnis = new StringBuffer(dnisPref);
EVT evt;
service:
while(true) try {
dnis.setLength(dnisPref.length());
dnisl = 0;
clear();
beginService();
// Stay in reset...
do {
evt = serviceWaitEvent(R2Idle);
// Just in case we are resetting from OFFH timeout...
/* Longer description: We are always xa && !xb here,
* but for the case that we give up waiting for line, in which
* case we are !xa && !xb, and should wait forever until rb,
* then go xa && !xb */
if (!xa && !xb && rb)
dtiDev.setsig(xa = true, xb = false);
/* evt is null only when timeout, but AOFF events are filtered by service.
* we stay here until we either see idle for some time or get an event
*/
} while (!(xa && !rb) || (evt == null && !(ra && !rb)));
if (evt == null) {
// We are ok for dial out
linestate = IDLE;
setState(FREE);
try {
evt = serviceWaitEvent();
} catch (ChannelException ie) {
// Somebody is asking me to leave, outdial ?
if (linestate != OFFH)
setState(OOS); // This should not happen...
return;
}
}
// event should be AOFF, and state RSEIZED
if (linestate != RSEIZED) {
System.err.println("Ignoring " + evt);
continue service;
}
voiceDev.r2_fenable();
call = new Call(R2CASChannel.this);
ani = null;
getDnis:
while (true) {
evt = serviceWaitEvent(R2InterDigit);
if (evt == null) {
// Timeout in incomming dial
abortRings("InterDigit timeout");
continue service;
}
if (evt.type == EVT.TDX_CST
&& evt.cstevt == EVT.DE_TONEON) {
r2tone = evt.cstdata;
dnisl++;
switch(r2tone) {
case Voice.SIGI_1:
dnis.append('1');
break;
case Voice.SIGI_2:
dnis.append('2');
break;
case Voice.SIGI_3:
dnis.append('3');
break;
case Voice.SIGI_4:
dnis.append('4');
break;
case Voice.SIGI_5:
dnis.append('5');
break;
case Voice.SIGI_6:
dnis.append('6');
break;
case Voice.SIGI_7:
dnis.append('7');
break;
case Voice.SIGI_8:
dnis.append('8');
break;
case Voice.SIGI_9:
dnis.append('9');
break;
case Voice.SIGI_10:
dnis.append('0');
break;
case Voice.SIGI_15:
break getDnis;
default:
// Unexpected forward signal
abortRings("Unexpected forward" + evt);
continue service;
}
if (dnisl < inDnisLength) {
voiceDev.r2_sendb(Voice.SIGA_1, r2tone);
} else {
break;
}
} else if (evt.type == EVT.TDX_CST &&
evt.cstevt == EVT.DE_TONEOFF) {
// Ignore, forward off
} else if (evt.type == EVT.TDX_PLAYTONE) {
// Ignore, backward completed
} else {
abortRings("Unexpected " + evt);
continue service;
}
}
call.dnis = dnis.toString();
linestate = ICALL;
if (handler != null) {
endService();
handler.handleCall(call);
} else {
// Reject with congestion
voiceDev.r2_sendb(Voice.SIGB_4, r2tone);
do {
evt = serviceWaitEvent();
} while (evt.type != EVT.TDX_PLAYTONE);
}
}
catch (ChannelException ce) {}
finally {
endService();
}
}
// abort incomming due to protocol error
private void abortRings(String error) {
EVT evt;
System.err.println("Rings: " + error);
setState(OOS);
voiceDev.stop();
voiceDev.r2_fdisable();
voiceDev.r2_sendbp(Voice.SIGA_4);
do {
evt = serviceWaitEvent();
} while (!ra && evt.type != EVT.TDX_PLAYTONE);
if (call != null) call.drop();
}
public String toString() {
return "R2CASChannel on " + dtiDev + "/" + voiceDev;
}
public void setFree(boolean x) {
freeAccept = x;
}
public void setA3B6(boolean x) {
A3B6Accept = x;
}
public void setDnisLength(int n) {
inDnisLength = n;
}
static TNGEN ringLead = new TNGEN(200, -40, 20) ;
static TNGEN ring = new TNGEN(440, -10, 100) ;
static TNGEN ringSilence = new TNGEN(200, -40, 200);
static TPT stdTPT = new TPT();
static Thread ringer = null;
static EVT ringerEvt = null;
void accept() {
if (linestate != ICALL)
throw new ChannelException("accept(): wrong state");
try {
EVT evt = null;
boolean acceptOne = false;
if (freeAccept || A3B6Accept){
voiceDev.r2_sendb(Voice.SIGA_3, r2tone);
while (true) {
evt = serviceWaitEvent(R2InterDigit);
if (evt == null) {
// Timeout in incomming dial
abortIcall("InterDigit timeout");
}
if (evt.type == EVT.TDX_CST
&& evt.cstevt == EVT.DE_TONEON) {
r2tone = evt.cstdata; // category
if (freeAccept)
voiceDev.r2_sendb(Voice.SIGB_7, r2tone);
else
voiceDev.r2_sendb(Voice.SIGB_6, r2tone);
break;
} else if (evt.type == EVT.TDX_CST &&
evt.cstevt == EVT.DE_TONEOFF) {
// Ignore, forward off
} else if (evt.type == EVT.TDX_PLAYTONE) {
// Ignore, backward completed
} else {
abortIcall("Unexpected " + evt);
}
}
} else
voiceDev.r2_sendb(Voice.SIGA_6, r2tone);
// Accept end: forward cat off & back done
while (true) {
evt = serviceWaitEvent();
if (evt.type == EVT.TDX_PLAYTONE ||
(evt.type == EVT.TDX_CST && evt.cstevt == EVT.DE_TONEOFF)) {
if (acceptOne) {
try {
Thread.sleep(R2ConnDelayIn);
} catch (InterruptedException ie) {
//nah, catch it elsewhere
Thread.currentThread().interrupt();
};
break;
}
acceptOne = true;
} else {
abortIcall("Unexpected " + evt );
}
}
voiceDev.r2_fdisable();
ringsSent = 0;
linestate = RINGS;
voiceDev.playtone(ringLead, stdTPT);
ringPhase = true;
ringerEvt = null;
Runnable r = new Runnable() {
public void run() {
try {
ringerEvt = serviceWaitEvent();
} catch (ChannelException ce) {}
ringer = null;
if ((Dialogic.debug & Dialogic.DEBUG_CHANNEL) != 0)
System.out.println(R2CASChannel.this.toString() + ": ringer off");
}
};
ringer = new Thread(r, this.toString() + " ringer");
ringer.start();
} finally {
endService();
}
}
void answer(int rings) {
if (linestate == ICALL)
accept();
if (linestate != RINGS)
throw new ChannelException("answer(): wrong state");
// Ring cycle
long now = System.currentTimeMillis();
long conn = call.startTime() + rings * 3000; // 3 secs each
if (conn > now && ringer != null)
try {
ringer.join(conn - now);
} catch (InterruptedException ie) {}
if (linestate != RINGS) {
linestate = RESET;
setState(OOS);
throw new ChannelException("answer(): " + ringerEvt);
}
linestate = IN;
if (ringer != null) {
Thread r = ringer; // Ringer clears its reference!
r.interrupt();
try {
r.join();
} catch (InterruptedException ie) {}
}
voiceDev.stop();
dtiDev.setsig(xa = false, xb = true);
}
void reject(int reason) {
if (linestate != ICALL)
throw new ChannelException("reject(): wrong state");
try {
linestate = IN; // Actually rejecting, but different from ICALL.
setState(OOS);
int bsig = Voice.SIGA_4;
EVT evt;
switch(reason) {
case BUSY:
bsig = Voice.SIGB_3;
break;
case BADNUMBER:
bsig = Voice.SIGB_5;
break;
case NOTINSERVICE:
bsig = Voice.SIGB_8;
break;
case CONGESTION:
default:
bsig = Voice.SIGA_4;
}
if (bsig != Voice.SIGA_4) {
// Switch to B
voiceDev.r2_sendb(Voice.SIGA_3, r2tone);
while (true) {
evt = serviceWaitEvent(R2InterDigit);
if (evt == null) {
// Timeout in incomming dial
abortRings("Reject interDigit timeout");
clear();
return;
}
if (evt.type == EVT.TDX_CST
&& evt.cstevt == EVT.DE_TONEON) {
r2tone = evt.cstdata; // category
break;
} else if (evt.type == EVT.TDX_CST &&
evt.cstevt == EVT.DE_TONEOFF) {
// Ignore, forward off
} else if (evt.type == EVT.TDX_PLAYTONE) {
// Ignore, backward completed
} else {
abortRings("Reject unexpected " + evt);
clear();
return;
}
}
}
voiceDev.r2_sendb(bsig, r2tone);
do {
evt = serviceWaitEvent();
} while (!ra && evt.type != EVT.TDX_PLAYTONE);
clear();
} finally {
endService();
}
}
void dial(Call call, String number) {
if (linestate != IDLE)
throw new ChannelException("dial(): wrong state");
try {
linestate = OFFH;
if (serviceThread != null) {
Channel.stopGroup(this);
serviceThread.interrupt();
/* Service thread will normally die,
* but simultaneous seizure may prevent that from happening... */
try {
serviceThread.join(500);
}
catch(InterruptedException ie) {
Thread.currentThread().interrupt();
}
// Give up if it did not quit...
if (serviceThread.isAlive()) {
System.err.println("Seizure failure: service not quitting");
throw new ChannelException("dial(): seizure failure");
}
serviceThread = null;
}
this.call = call;
setState(OUTGOING);
EVT evt = null;
// Here we go...
dtiDev.setsig(xa = false, xb = false); // line seizure
evt = serviceWaitEvent(R2OHDelay);
// event should be BON, and state DIAL
if (linestate != DIAL) {
if (evt != null && evt.type == EVT.DTEV_SIG && !ra) {
// Simultaneous seizure...
System.err.println("Simultaneous seizure");
setState(OOS);
try {
Thread.sleep(R2SimSeizureDelay);
} catch (InterruptedException ie) {
//nah, catch it elsewhere
Thread.currentThread().interrupt();
};
} else if (evt != null) {
System.err.println("Seizure failure: " + evt);
setState(OOS);
} else {
System.err.println("Seizure failure: timeout");
setState(OOS);
}
throw new ChannelException("dial(): seizure failure");
}
// Dial...
voiceDev.r2_benable();
int dnisp = 0;
int r2tone = 0;
boolean phaseB = false;
int anip = 0;
sendDigit(number, 0, false);
sendDnis:
while (true) {
evt = serviceWaitEvent(R2InterDigit);
if (evt == null) {
// Timeout
throw new ChannelException("dial(): dial timeout");
}
if (evt.type == EVT.TDX_CST
&& evt.cstevt == EVT.DE_TONEOFF) {
r2tone = evt.cstdata;
// Reset ANI pointer
if (r2tone != Voice.SIGA_5)
anip = 0;
if (!phaseB) {
switch(r2tone) {
case Voice.SIGA_1: // next
dnisp++;
break;
case Voice.SIGA_2: // previous
dnisp--;
if (dnisp < 0) dnisp = 0;
break;
case Voice.SIGA_7: // prev^2
dnisp-= 2;
if (dnisp < 0) dnisp = 0;
break;
case Voice.SIGA_8: // prev^3
dnisp-= 3;
if (dnisp < 0) dnisp = 0;
break;
case Voice.SIGA_9: // last (again)
break;
case Voice.SIGA_10: // start over
dnisp = 0;
break;
case Voice.SIGA_3: // Categ/go B
voiceDev.r2_sendf(Voice.SIGII_1); // Abo std
phaseB = true;
continue sendDnis;
case Voice.SIGA_4: // Congestion
throw new BusyException("dial(): Congestion");
case Voice.SIGA_5: // Categ/ANI
if (anip == 0)
voiceDev.r2_sendf(Voice.SIGII_1); // Abo std
else
voiceDev.r2_sendf(Voice.SIGII_12); // no ANI
anip++;
continue sendDnis;
case Voice.SIGA_6: // Accept
linestate = DIALOK;
break sendDnis;
default:
// Unexpected backward signal
throw new ChannelException("dial(): Unexpected backward" + evt);
} // backward tone off case
sendDigit(number, dnisp, false);
} else {
// phase B
switch(r2tone) {
case Voice.SIGA_3: // Congestion
throw new BusyException("dial(): Busy");
case Voice.SIGA_4: // Congestion
throw new BusyException("dial(): B Congestion");
case Voice.SIGA_5: // Categ/ANI
if (anip == 0)
voiceDev.r2_sendf(Voice.SIGII_1); // Abo std
else
voiceDev.r2_sendf(Voice.SIGII_12); // no ANI
anip++;
continue sendDnis;
case Voice.SIGA_6: // Accept
linestate = DIALOK;
break sendDnis;
case Voice.SIGA_7: // Free Accept
linestate = DIALOK;
pulses = -1; // will compensate with pulses++ at connect
break sendDnis;
default:
// Unexpected backward signal
throw new ChannelException("dial(): Unexpected backward B " + evt);
}
}
} else if (evt.type == EVT.TDX_CST &&
evt.cstevt == EVT.DE_TONEON) {
// Ignore, backward on
} else if (evt.type == EVT.TDX_PLAYTONE) {
// Ignore, forward completed
} else {
throw new ChannelException("dial(): Unexpected " + evt);
}
} // SendDnis
// We are in DIALOK state, let user wait for connect (OUT state)
voiceDev.r2_bdisable();
while (serviceWaitEvent(R2ConnDelayOut) != null) {}
} finally {
endService();
}
}
private void sendDigit(String number, int index, boolean sendI15) {
if (index >= number.length()) {
// XXX protocol dependent ?
if (sendI15)
voiceDev.r2_sendf(Voice.SIGI_15);
// Stay silent and wait for pulsed answer...
} else {
switch(number.charAt(index)) {
case '0':
voiceDev.r2_sendf(Voice.SIGI_10);
break;
case '1':
voiceDev.r2_sendf(Voice.SIGI_1);
break;
case '2':
voiceDev.r2_sendf(Voice.SIGI_2);
break;
case '3':
voiceDev.r2_sendf(Voice.SIGI_3);
break;
case '4':
voiceDev.r2_sendf(Voice.SIGI_4);
break;
case '5':
voiceDev.r2_sendf(Voice.SIGI_5);
break;
case '6':
voiceDev.r2_sendf(Voice.SIGI_6);
break;
case '7':
voiceDev.r2_sendf(Voice.SIGI_7);
break;
case '8':
voiceDev.r2_sendf(Voice.SIGI_8);
break;
case '9':
voiceDev.r2_sendf(Voice.SIGI_9);
break;
default:
throw new ChannelException("dial(): invalid number ("
+ number + ")");
}
}
}
String ani() {
if (ani != null)
return ani;
if (linestate != ICALL) {
ani = "";
return ani;
}
EVT evt;
StringBuffer anibuf = new StringBuffer();
int anil = 0;
try {
beginService();
voiceDev.r2_sendb(Voice.SIGA_5, r2tone);
getANI:
while (true) {
evt = serviceWaitEvent(R2InterDigit);
if (evt == null) {
// Timeout in incomming dial
abortIcall("Ani timeout");
}
if (evt.type == EVT.TDX_CST
&& evt.cstevt == EVT.DE_TONEON) {
r2tone = evt.cstdata;
anil++;
switch(r2tone) {
case Voice.SIGI_1:
anibuf.append('1');
break;
case Voice.SIGI_2:
anibuf.append('2');
break;
case Voice.SIGI_3:
anibuf.append('3');
break;
case Voice.SIGI_4:
anibuf.append('4');
break;
case Voice.SIGI_5:
anibuf.append('5');
break;
case Voice.SIGI_6:
anibuf.append('6');
break;
case Voice.SIGI_7:
anibuf.append('7');
break;
case Voice.SIGI_8:
anibuf.append('8');
break;
case Voice.SIGI_9:
anibuf.append('9');
break;
case Voice.SIGI_10:
anibuf.append('0');
break;
case Voice.SIGI_12: // ANI rq denied
case Voice.SIGI_15: // ANI rq finished
break getANI;
default:
// Unexpected forward signal
abortIcall("Ani unexpected " + evt);
}
voiceDev.r2_sendb(Voice.SIGA_5, r2tone);
} else if (evt.type == EVT.TDX_CST &&
evt.cstevt == EVT.DE_TONEOFF) {
// Ignore, forward off
} else if (evt.type == EVT.TDX_PLAYTONE) {
// Ignore, backward completed
} else {
abortIcall("Ani unexpected " + evt);
}
}
ani = anibuf.toString();// .substring(1); // includes category
} finally {
endService();
}
return ani;
}
// abort ICALL (ani/accept) due to protocol error
private void abortIcall(String error) {
EVT evt;
System.err.println("Icall: " + error);
setState(OOS);
voiceDev.stop();
voiceDev.r2_fdisable();
voiceDev.r2_sendbp(Voice.SIGA_4);
ani = ""; // prevent late request of ANI
do {
evt = serviceWaitEvent();
} while (!ra && evt.type != EVT.TDX_PLAYTONE);
if (call != null) call.drop();
clear();
throw new HangUpException();
}
int pulses() {
return pulses;
}
synchronized void clear() {
if (linestate == RESET)
return;
if (ani == null) ani = ""; // Prevent late ANI request
super.clear();
int fromState = linestate;
linestate = RESET; // No need for flush to throw an event
voiceDev.stop();
voiceDev.r2_fdisable();
voiceDev.r2_bdisable();
voiceDev.clear();
dtiDev.listen(voiceDev);
voiceDev.listen(dtiDev);
flush();
pulses = 0;
ani = "";
switch(fromState) {
case IDLE:
case RESET:
break;
case RINGS:
if (ringer != null) ringer.interrupt();
case RSEIZED:
case ICALL:
// dropping in advance ?
if (ra)
// They dropped
dtiDev.setsig(xa = true, xb = false);
// else
// We drop. But lets wait...
break;
case IN:
// dropping...
if (ra)
// They dropped
dtiDev.setsig(xa = true, xb = false);
else
// We drop.
dtiDev.setsig(xa = true, xb);
break;
case OFFH:
// Wait for seizure conf
break;
case DIAL:
case DIALOK:
case OUT:
case INIT:
dtiDev.setsig(xa = true, xb = false);
break;
}
if (serviceThread == null) {
serviceThread = new Thread(group, this, dtiDev.name + "/" + voiceDev.name + " service");
serviceThread.start();
}
}
/**
* service()
* Our line state service fn
* Run in channel thread (like a interrupt time handler :-)
* Can "eat" the event if it should not get into "user space"
* or even change it by returning null or other event
*/
protected EVT service(EVT evt) {
if (dtiDev.source(evt)) {
switch(evt.type) {
case EVT.DTEV_SIG:
ra = (evt.data & A)!= 0;
rb = (evt.data & B)!= 0;
if (linestate == INIT) {
evt = null;
break;
}
if ((evt.data & CA) != 0) {
if (ra) {
if (setA()) evt = null;
} else {
if (clrA()) evt = null;
}
} else if ((evt.data & CB) != 0) {
if (rb) {
if (setB()) evt = null;
} else {
if (clrB()) evt = null;
}
} else if ((evt.data & WINK) != 0) {
pulses++;
return null;
}
break;
case EVT.DTEV_E1ERRC:
switch(linestate) {
case IN:
case OUT:
if (call != null) call.drop();
clear();
throw new HangUpException();
}
break;
}
} else if (voiceDev.source(evt)) {
if (evt.type == EVT.TDX_PLAYTONE) {
if (linestate == RINGS) {
if (ringPhase) {
voiceDev.playtone(ring, stdTPT);
ringPhase = false;
ringsSent++;
} else {
voiceDev.playtone(ringSilence, stdTPT);
ringPhase = true;
}
return null;
}
}
}
return evt;
}
/**
* setA()
* logic to apply to A bit going high.
* Returns true if event was serviced, i.e., should not be passed along
*/
private boolean setA() {
switch(linestate) {
case RESET:
// They drop after us in incoming ?
dtiDev.setsig(xa = true, xb = false);
break;
case IDLE: // should not happen...
case RSEIZED: // premature abort, handled elsewhere
setState(OOS);
break;
case RINGS: // abort
if (ringer != null) ringer.interrupt();
// PASSTHROUGH
case ICALL: // late abort
linestate = IN; // prevent ring cycle loop (if RINGS)
// prevent late ani request (if ICALL)
// PASSTHROUGH
case IN:
// Incoming hang up
if (call != null) call.drop();
clear();
throw new HangUpException();
case OUT:
// Remote "forced" clearing...
if (call != null) call.drop();
clear();
throw new HangUpException();
}
return true;
}
/**
* clrA()
* logic to apply to A bit going low.
* Returns true if event was serviced, i.e., should not be passed along
*/
private boolean clrA() {
switch(linestate) {
case RESET:
if (rb)
break;
// Fall through if we are in guard time...
case IDLE:
// answer ?
dtiDev.setsig(xa = true, xb = true);
linestate = RSEIZED;
setState(INCOMING);
return false;
case OFFH:
// Simultaneous seizure...
linestate = ERROR;
case DIAL:
// XXX Answer before R2 finished ???
return false;
case DIALOK:
// Answer
linestate = OUT;
pulses++;
if (call != null) call.connect();
return false;
}
return true;
}
/**
* setB()
* logic to apply to B bit going high.
* Returns true if event was serviced, i.e., should not be passed along
*/
private boolean setB() {
switch(linestate) {
case IDLE:
// Line blocked ?
linestate = RESET;
setState(OOS);
return false; // Let serviceChannel know we are not idle anymore
case RESET:
// late seizure conf ?
setState(OOS); // just in case
dtiDev.setsig(xa = true, xb = false);
break;
case OFFH:
// seizure conf
linestate = DIAL;
return false;
}
return true;
}
/**
* clrB()
* logic to apply to B bit going low.
* Returns true if event was serviced, i.e., should not be passed along
*/
private boolean clrB() {
switch (linestate) {
case RESET:
// WAIT for serviceChannel to set it idle... 9/9/01
// if (ra) linestate = IDLE;
// setState(FREE);
return true;
case OFFH:
case DIAL:
case DIALOK:
setState(OOS);
if (call != null) call.drop();
clear();
throw new ChannelException("Abort");
}
return false;
}
//{{DECLARE_CONTROLS
//}}
}