This chapter describes the isdndemo demonstration program supplied with AG ISDN. The program is an example of a digital trunk application that uses the layer 3 ISDN signaling interface. It shows how to use the ISDN message-oriented API and the AG Access or CT Access API to receive and place calls on a primary rate ISDN trunk.
The program supports a single T1 or E1 trunk. Multiple instances of the program can be run to support multiple trunks. With a command-line option, the user can specify the ISDN country/signaling system variant to use.
A single-threaded and a multi-threaded version of this program may be created with a simple variation in the included makefile:
The default behavior of the program is to accept inbound calls. Outbound calls can be generated by specifying the appropriate command-line option.
isdndemo consists of the following files:
|
File |
Description |
|
isdndemo.c |
The main application program with event processing functions. |
|
isdndemo.h |
Header file for the isdndemonstration program. |
|
isdnstmc.c |
The ISDN state machine implementation. |
|
isdnccms.c |
Functions to build ISDN call control messages (request buffers). |
|
os_rts.c |
Operating-system-specific routines. |
|
os_rts.h |
Operating-system-specific header file. |
|
isdnlog.c |
ISDN event logging mechanism. |
|
demolib.c, demolib.h |
NMS standard distribution (used only when the demonstration program is compiled for AG Access). Only the getopt function from this library is used. |
|
getopt.c |
NMS standard distribution (used only when the demonstration program is compiled for CT Access). |
To compile and use isdndemo, you need:
Note for AG-T1/E1 users: ISDN is only supported on AG-T1 and AG-E1 boards revision D-1 or later. If you are using AG-T1 or AG-E1 boards that were not provided with your AG ISDN package, check the revision number.
To compile isdndemo, do one of the following:
|
For this API... |
Under this OS... |
Go to this directory... |
Enter... |
|
CT Access |
Windows NT |
c:\nms\ctaccess\demos\isdndemo |
nmake |
|
CT Access |
OS/2 |
c:\nms\ctaccess\demos\isdndemo |
makedemo |
|
CT Access |
UNIX |
/opt/nms/ctaccess/demos/isdndemo |
make |
|
AG Access |
Windows NT |
c:\nms\agaccess\demos\isdndemo |
nmake |
|
AG Access |
OS/2 |
c:\nms\agaccess\demos\isdndemo |
makedemo |
|
AG Access |
UNIX |
/opt/nms/agaccess/demos/isdndemo |
make |
For more information, see the readme file that came with the AG ISDN software package.
When isdndemo is run with no command-line options, the program defaults to AG board 0. (The board number for each board is specified for it in the AG configuration file.) The program automatically determines the board type, and runs one of the following protocols:
|
Board |
Default protocol |
|
AG Quad T |
AT&T 5ESS10 |
|
AG Quad Connect T |
AT&T 5ESS10 |
|
AG Dual T |
AT&T 5ESS10 |
|
AG-T1 |
AT&T 5ESS10 |
|
AG Quad E |
EuroISDN |
|
AG Quad Connect E |
EuroISDN |
|
AG Dual E |
EuroISDN |
|
AG-E1 |
EuroISDN |
When no command-line options are specified, the program assumes that it is not placing any outbound calls but is only accepting inbound calls.
The default behavior can be changed using any of the command-line options listed below. Specify options using a '-' before the letter, followed by a numeric value (if required). Whitespace between the letter and the arguments is optional. The order of the command-line options does not matter.
The demonstration program's command-line options are:
|
Option |
Meaning |
Defaults |
|
-a |
0 | |
|
-o outlines |
0 | |
|
-I inlines |
Number of lines on which to accept inbound calls. Note: Specify this option only if you want support only for a part of the trunk. |
T1: 23 |
|
-l |
Log ISDN messages. Messages are logged to the file isdnbb.log, where bb is the board number. |
No logging. |
|
-p protocol |
Protocol variant to run. Allowed values: Value Protocol |
AG Quad T, AG Quad Connect T, AG Dual T, AG Quad E, AG Quad Connect E, AG Dual E, |
|
-d dialstring |
1234567 | |
|
-n |
TE | |
|
-? |
N/A |
The following command line specifies USA National ISDN 2 on the second AG board in a system (Board 1 in the ag.cfg file) and places calls on the first 10 channels:
isdndemo -b 1 -p 20 -o 10
The single-threaded version of isdndemo uses a single thread (process) to control multiple voice ports. This section discusses the generic structure of the program focusing on the single-threaded AG Access version. The CT Access and the AG Access versions are virtually identical, except for the code associated with initialization and event retrieval.
Figure 20 illustrates the program structure of the single-threaded version of the demonstration program.

Figure 20: Single-Threaded Demonstration Program Structure
The demonstration program program creates and stores a number of application contexts. These contexts are kept in an array of structures stored in an allocated memory area. Each application context has its own handle to provide voice functionality to the voice line. Also in this allocated memory area are a number of flags and parameters global to the system. This data structure is called mem_area and is defined in the file isdndemo.h. A global pointer to this structure, SM, is maintained in the program.
isdndemo first parses the command-line options and determines whether they are valid for the AG board being used. For example, it ensures that the user is not attempting to utilize more voice channels than exist on the physical trunk. To do this, isdndemo calls adiGetBoardInfo immediately after the AG driver is opened with adiOpenDriver. If there are any inconsistencies, the program exits with a warning message.
It If the command line is valid, the isdndemo function open_port is called. open_port opens a number of CTA contexts. It opens one CTA context for each voice channel it will handle, plus one CTA context for the D channel. For example, for a T1 trunk, the application opens 24 CTA contexts (23 CTA contexts for B channels plus one for the D channel). For an E1 trunk, the application opens 31 CTA contexts (30 for voice and one for the D channel).
To open a CTA context, the stream and timeslot to be used by the DSP resource must be specified. The open_port function also requires the number of the B channel to associate with the opened CTA context. The B channel supplied with the DSP stream and timeslot is the default connection made by agmon4 when the AG boards are loaded (see the installation manual for your AG board for more information). This binding in the CTA context structure makes it unnecessary to re-make any switching connections. If less than the full number of B channels are started, calls on B channel timeslots not associated with opened CTA contexts are rejected in this demonstration program.
Once the CTA contexts have been allocated, the application starts the "no call control" TCP (NOCC.tcp) on all CTA contexts except the last one. This enables voice processing capability on all CTA contexts except the one reserved as a communication path to the D channel.
When all of the TCPs have been started, isdn_start starts the ISDN protocol stack on the last CTA context, to activate the D channel. To start the protocol stack, the application invokes isdnStartProtocol with the NAI specified on the command line (or NAI 0 if not specified). If the protocol stack starts properly, the event ISDNEVN_START_PROTOCOL occurs with a return value of SUCCESS. (Any other return value indicates that a stack failed to start. isdndemo terminates if a problem occurs.) The ISDNEVN_START_ PROTOCOL event is processed by isdn_start. This function does not return until the ISDN protocol stack has been started.
Once the protocol stack has been started, isdndemo is ready to accept inbound calls.
If isdndemo is set up to dial out (via its command-line options), it places outbound calls by invoking make_call. Note that if the system is placing outbound calls on fewer timeslots than are available in the system, the first n timeslots are used, where n is the number of channels assigned to call placement with the -o command-line option. For example, if isdndemo is run with the command:
isdndemo -o 10
...and the board is an AG-E1 board, outbound calls are placed on logical timeslots 0 through 9. isdndemo accepts inbound calls on any idle channel.
isdndemo is extremely simple. When an inbound call occurs, the system accepts the call, plays a prompt, and then waits for a disconnect. In outbound mode, isdndemo plays the same prompt but initiates hang up after hold_time seconds (hold_time is an internal program constant).
The main program loop is an infinite loop. At the top of the loop, it calls os_wait_event_sem. This function waits for an event. If no event occurs within a specified amount of time, os_wait_event_sem returns GOT_TIMEOUT.
If an event occurs, GOT_EVENT is returned. isdndemo retrieves the event by calling adiFetchAndProcess. isdndemo then identifies the CTA context associated with the event by checking the userid. isdndemo does so to determine whether the event is a call control event from the ISDN D channel or an ADI event directed to voice channel processing. If the event is an ISDN call control event, isdndemo proceeds as discussed in section 9.3.3. Otherwise, isdndemo proceeds as discussed in section 9.3.4.
If the userid indicates that a received event is an ISDN call control event, the D channel state machine function, process_isdn_event, is called to process the event.
Each ISDN message is a composite event. Within the event is an ISDN packet, which contains an ISDN message. Each message is processed based on the following parts:
For call control messages (connection indication, hang up, etc.), the sender is always ENT_CC - the call control entity. If process_isdn_event determines that the sender is the call control entity, the function process_cc_state is called to process the event.
Note that a debugging routine called LogReceivedMessage is called in process_isdn_message. This function shows how to decode numerous ISDN message buffers in a single routine.
With inbound calls, the protocol stack generates the connection id. The connection id assigned is the highest unused value starting with 39. For example, if connection ids 39 and 38 are already allocated to calls, the protocol stack assigns id 37 to the next call.
For outbound calls, the initial request to "dial" contains a connection id to be used by the protocol stack. To avoid any chance of collision, the demonstration program uses connection ids beginning with 0. The program keeps track of which connection ids are in use and which are available.
The detailed processing of ISDN information is performed in the function process_cc_state. This state machine is described in a subsequent section.
If the userid indicates that the event is associated with a voice channel, the B channel state machine, process_adi_event, is called. This routine processes the standard set of ADI events, such as ADIEVN_PLAYDONE. It also receives a special set of events that are generated by the D channel state machine, in order to maintain the functional partition between B and D channel processing. Refer to Section 9.3.5 for more details on the meaning and usage of these events. No D channel events are passed to this routine.
In AG Access, isdndemo uses adiLoopbackEvent to maintain separation between call control processing of the message stream on the D channel and application (B channel) processing. (For CT Access, isdndemo uses ctaQueueEvent.) Events received by the D channel are looped back to a B channel CTA context for application processing.
This application separates the application processing from the call control processing. Because of this, a mechanism is required for initiating application processing. This mechanism works as follows: when the D channel state machine connects to an incoming call (receiving, for example, an ACU_CONN_CO message from the D channel), a loop back event is created indicating the arrival of the call. When we exit the D channel processor to the main loop, the loopback event is waiting in the event queue. Since this event has a userid associated with a particular B channel event, the main loop invokes the B channel processing code in process_adi_event.
The following table gives the loopback events used in the demonstration program.
|
Event Name |
Direction B Channel D Channel |
Description |
|
|
Indicates receipt of an incoming call. | |
|
|
Indicates that outbound call is connected. | |
|
|
Indicates that a remote hang up has occurred. | |
|
|
Requests the D channel state machine to place a call. | |
|
|
Request the D channel state machine to hang up a call. |
isdndemo can run as a multi-threaded application under operating systems that support this programming model. The program structure is fundamentally identical to the one described above. This section describes the differences in functionality of the multi-threaded version of the program.
Figure 21 shows the structure of the multi-thread demonstration program.
The multi-threaded version of isdndemo is similar to the single-threaded version. The key difference is that each B channel CTA context is run in its own thread. Each thread allocates its own driver handle and muxhandle. These handles are placed in the same CTA context structure used by the single threaded version of the program. The initialization section creates a single thread for each of the requested application instances, passing the B channel timeslot owned by the thread during its lifetime. The functionality of each of these threads is identical to the ADI event processing code in the single-threaded version. Figure 21 illustrates the program structure of the multi-threaded version of the demonstration program.

Figure 21: Multi-Threaded Demonstration Program Structure
If the application is placing outbound calls, these calls are initiated in the main thread.
The main process thread is an infinite while loop. This loop performs only D channel processing. All B channel processing is performed by the threads. As discussed above, when a call arrives on the D channel, a loop back event is created to "kick-off" application processing. In the multi-threaded version, this message is placed in the event queue of the appropriate B channel thread. The loopback event demo_connect_in is processed by the B channel process, just as in the single-threaded version of isdndemo.
When an ISDN event occurs, the event ISDNEVN_RCV_MESSAGE is in the AG Access or CT Access event ID in the event structure.5 To decode the message, the message code, sender, recipient, and connection ID information is unpacked. All messages also contain additional information in a message-specific buffer. The debugging function LogReceivedMessage provides an example of how to decode many of these messages. The actual processing of these buffers is done in the state functions contained in isdnstmc.c. For example, inbound call message buffers are decoded in process_wait_incoming.
In isdndemo, a simple state machine is implemented to handle ISDN call control. This is illustrated in Figure 22.

Figure 22: isdndemo State Machine
This state machine is implemented in the module isdnstmc.c.
The following table shows the correspondence between the states shown above and the functions implemented in isdnstmc.c:
|
State Name |
Description |
Function |
|
ST_NULL |
Idle |
|
|
ST_AWAITING_INCOMING_CALL |
Wait for incoming call |
|
|
ST_AWAITING_CONNECT |
Waiting to connect |
|
|
ST_AWAITING_OUTGOING_CALL |
Wait for outgoing call |
|
|
ST_ACTIVE |
Active - call connected |
|
|
ST_AWAITING_CLEARANCE |
Wait for clear confirmation |
To send a message to the ISDN protocol stack, isdndemo first builds a message-specific data buffer. For example, to place an outbound call, cc_build_conn_rq builds the buffer for a connection request.
Note: The file isdnccms.c contains functions to build most requests. The functions implemented in this module use the macros defined in isdnacu.h to construct the messages. We strongly recommend that you use the macros given in this file to both encode and decode ISDN message buffers.
Once the message buffer for the protocol stack has been built, initialize_imsg builds an ISDN_MESSAGE structure. This structure contains information such as the message code, which entity the message is for, from whom it was sent, etc.
Finally, mySendMessage sends the message to the AG board via a call to isdnSendMessage.
When an inbound call is first detected, an ACU_CONN_IN message (connection indication message) is detected coming from ENT_CC. This event causes the function process_cc_state to be called.
isdndemo requires that a CTA context exists for the B channel on which the call is taking place. This ensures that a DSP resource is available to handle the call. Once this is satisfied, a state transition from the NULL state to the state ST_AWAITING_INCOMING_CALL is assigned to the CTA context.
In the function process_wait_incoming, the called (DNIS) and calling number (ANI) are decoded. To accept the call, a connect response message (ACU_CONN_RS) is built. The event ACU_CONN_CO is a confirmation that the call has been established and causes a transition to the active state.
Following is the text of a log trace of isdndemo receiving an inbound call. Commands from isdndemo to the protocol stack are indicated by:
CALL CONTROL <= APPLICATION
Events from the protocol stack are indicated by:
CALL CONTROL => APPLICATION.
The arrow indicates the direction of information flow.
Wed Nov 13 16:45:30 CALL CONTROL => APPLICATION msg = ACU_CONN_IN Calling Phone Number = 5086501340 Called Phone Number = 1234567 Connection on physical channel 10 Got a SENDING COMPLETE. service = VOICE CRN 39 Wed Nov 13 16:45:30 CALL CONTROL <= APPLICATION msg = ACU_CONN_RS CRN 39 Wed Nov 13 16:45:30 CALL CONTROL => APPLICATION msg = ACU_ALERT_IN CRN 39 state = WAIT_INCOMING Wed Nov 13 16:45:30 CALL CONTROL => APPLICATION msg = ACU_CONN_CO CRN 39 state = WAIT_INCOMING Wed Nov 13 16:45:51 CALL CONTROL => APPLICATION msg = ACU_CLEAR_IN (network cause = 10) CRN 39 state = ACTIVE Wed Nov 13 16:45:51 CALL CONTROL <= APPLICATION msg = ACU_CLEAR_RS CRN 39 Wed Nov 13 16:45:51 CALL CONTROL => APPLICATION msg = ACU_CLEAR_CO (cause = hang up) (network cause = 10) CRN 39 state = WAIT_CLEARANCE
To place an outbound call, cc_build_conn_rq builds the "setup" message. Once the command is built, initialize_imsg initializes the ISDN message structure and sends the message to the AG board by invoking isdnSendMessage. The message sent is ACU_CONN_RQ.
At this point, ACU_PROGRESS_IN may be received from the network followed by ACU_ALERT_IN. The connection ID associated with this event is the user ID supplied to initialize_imsg and passed in the element add.conn_id field. If the call is successfully connected, ACU_CONN_CO is received; otherwise a hang up indication, ACU_CLEAR_CO, is received.
Following is the log trace of isdndemo placing an outbound call.
Wed Nov 13 16:40:44 CALL CONTROL <= APPLICATION msg = ACU_CONN_RQ CRN 1 Wed Nov 13 16:40:44 CALL CONTROL => APPLICATION msg = ACU_PROGRESS_IN CRN 1 state = NULL Wed Nov 13 16:40:44 CALL CONTROL => APPLICATION msg = ACU_ALERT_IN CRN 1 state = WAIT_OUTGOING Wed Nov 13 16:40:44 CALL CONTROL => APPLICATION msg = ACU_CONN_CO CRN 1 state = WAIT_OUTGOING Wed Nov 13 16:41:00 CALL CONTROL <= APPLICATION msg = ACU_CLEAR_RQ CRN 1 Wed Nov 13 16:41:00 CALL CONTROL => APPLICATION msg = ACU_CLEAR_CO (cause = hang up) (network cause = 10) CRN 1 state = ACTIVE
If the remote end hangs up, an ACU_CLEAR_IN event is detected. The application responds to this with an ACU_CLEAR_RS. The final event is an ACU_CLEAR_CO. The first event is a clearing indication; the second is a clearing confirmation.
To initiate a hang up, the system issues an ACU_CLEAR_RQ. The expected response event is ACU_CLEAR_CO.
Note that in each CTA context for the B channels, a flag is kept to indicate whether or not the channel is playing. This is because AG Access and CT Access does not automatically stop playing (or recording) if a disconnect occurs. If a hang up is detected and the system is still playing, adiStopPlaying is called to stop the function. There are alternative strategies to cope with this situation. For example, closing and reopening the CTA context will stop all DSP-related functions associated with the CTA context, including playing and recording.
In the MVIP switching model, B channels are numbered from 0 to 23 on a T1 trunk and from 0 to 29 on an E1 trunk. These numbers are contiguous. The ISDN protocol stack requires the physical timeslot number and not the NMS logical number. The physical timeslot numbers on a T1 trunk are 1 to 24 with the D channel occupying channel 24. On an E1 trunk, the physical timeslot numbers are 0 to 31. Channel 0 is for synchronization, 1 through 15 are B channels, 16 is the D channel, and 17 through 31 are the remaining B channels. The functions NMS_logical_to_physical and NMS_physical_to_logical perform the necessary conversions.
Natural MicroSystems, Inc.
100 Crossing Boulevard
Framingham, MA 01702
3 Use for the following countries: Austria, Denmark, Finland, Greece, Iceland, Ireland, Italy, Liechtenstein, Luxembourg, Netherlands, Norway, Portugal, and Spain
4 Note that this presumes that ENABLEMVIP in the file ag.cfg is set to NO. For details, see Section 4.2.
5 See header file adi.h.