// DEMODIAL.C - This is the BICOM 4LS Multi-line Dialing Program. // It will repeatedly dial telephone numbers on several // channels. Calling status for each call is displayed on // the screen. If pick-up (your voice) is detected, the // voice file "HELLO.VOX" will be played and the call is // terminated. // // Enter "demodial " at DOS prompt where n is optional // user-assigned hardware interrupt level. The standard // BICOM 4LS hardware interrupt is 3. // can be used to terminate this program at any time. // // BICOM (R) Multi-line Dialing Demo Program // Copyright (c) BICOM 1990, 1991 All rights reserved. // INCLUDES #include #include #include #include #include #include #include "sys\types.h" #include "sys\stat.h" #include "bcmlib.h" // BICOM standard header file // DEFINES // system definitions #define FOREVER 1 // while loop index in main function #define INTLVL 3 // standard H/W interrupt level #define NUMCHAN 4 // number of channels #define ESC 0x1B // escape key // channel state definitions #define ST_ONHOOK 0 // going on hook #define ST_WTCALL 1 // waiting to make next call #define ST_CALLING 2 // wait for call status #define ST_PLINTR 3 // play introduction #define ST_HALT 4 // do nothing #define ST_EXIT 5 // exiting #define NUM_STATE 6 // number of states // event definitions #define ONHK 0 // on hook complete #define LNDS 1 // line disconnect #define ENDF 2 // end of file on playback #define EXIT 3 // exiting #define CALL 4 // call status #define OFHK 5 // time out #define NUM_EVENT 6 // number of events // STRUCTURES static struct ChanEvent // channel event structure { int nChanNum; // channel number int nEventType; // event type occurred int nEventData; // event data } Event; // VARIABLES static TCB Tcb = { 0 }; // BICOM Task Control Block static int fhVoxFile; // DOS file handle for "hello.vox" static int nIntLvl; // user hardware interrupt level int nChanState[NUMCHAN+1]; // channel state variable array char szPhoneNum[NUMCHAN+1][15]={'\0'}; // storage for phone # to be called int nNumOfChan; // number of channels in system int nLineNum; // # of lines to use // PROTOTYPES void main(int, char **); void Init(void); void EventProcess(struct ChanEvent *); void StateTransit(struct ChanEvent *); int Play(int, char *, int); void GoOnhook_Entry(struct ChanEvent *); void GoOnhook_Exit(struct ChanEvent *); void WaitToCall_Entry(struct ChanEvent *); void WaitToCall_Exit(struct ChanEvent *); void Call_Entry(struct ChanEvent *); void Call_Exit(struct ChanEvent *); void PlayMsg_Entry(struct ChanEvent *); void PlayMsg_Exit(struct ChanEvent *); void Halt_Entry(struct ChanEvent *Event); void Halt_Exit(struct ChanEvent *Event); void Exit_Entry(void); // STATE TRANSITION TABLE // Current state is on the vertical axis. // Event is on the horizontal axis. // Each cell is the next state for a given state and an event occurred. int NextState[NUM_STATE] [NUM_EVENT] = { /* ONHK LNDS ENDF EXIT CALL OFHK */ /*ST_ONHOOK */ {ST_WTCALL, ST_ONHOOK, ST_ONHOOK, ST_EXIT, ST_ONHOOK, ST_ONHOOK }, /*ST_WTCALL */ {ST_ONHOOK, ST_ONHOOK, ST_ONHOOK, ST_EXIT, ST_ONHOOK, ST_CALLING}, /*ST_CALLING*/ {ST_ONHOOK, ST_ONHOOK, ST_ONHOOK, ST_EXIT, ST_PLINTR, ST_ONHOOK }, /*ST_PLINTR */ {ST_ONHOOK, ST_ONHOOK, ST_ONHOOK, ST_EXIT, ST_ONHOOK, ST_ONHOOK }, /*ST_HALT */ {ST_HALT, ST_HALT, ST_HALT, ST_EXIT, ST_HALT, ST_HALT } }; // LOOKUP TABLE // for entry and exit functions for each state struct LookUp { void (*pfnEntryFunction) (); void (*pfnExitFunction) (); } LookUpTbl[NUM_STATE] = { GoOnhook_Entry, GoOnhook_Exit, // ST_ONHOOK WaitToCall_Entry, WaitToCall_Exit, // ST_WTCALL Call_Entry, Call_Exit, // ST_CALLIN PlayMsg_Entry, PlayMsg_Exit, // ST_PLINTR Halt_Entry, Halt_Exit, // ST_HALT Exit_Entry // ST_EXIT }; //*************************************************************************** // go onhook entry function //*************************************************************************** void GoOnhook_Entry(struct ChanEvent *Event) { Bcm6_SetHook(Event->nChanNum,H_ONH); printf(" Enter: GoOnhook_Entry\n"); } //*************************************************************************** // go onhook exit function //*************************************************************************** void GoOnhook_Exit(struct ChanEvent *Event) { Event; // compress compiler printf(" Exit : GoOnhook_Exit\n"); } //*************************************************************************** // idle entry function //*************************************************************************** void WaitToCall_Entry(struct ChanEvent *Event) { Bcm6_SetHook(Event->nChanNum, H_OFFH); printf(" Enter: WaitToCall_Entry\n"); } //*************************************************************************** // idle exit function //*************************************************************************** void WaitToCall_Exit(struct ChanEvent *Event) { Event; // compress compiler printf(" Exit : WaitToCall_Exit\n"); } //*************************************************************************** // calling entry function //*************************************************************************** void Call_Entry(struct ChanEvent *Event) { int nReturnCode; char szNumber[20]; printf(" Enter: Call_Entry"); printf(", Calling \"%s\"\n",szPhoneNum[Event->nChanNum]); strcpy(szNumber, szPhoneNum[Event->nChanNum]); if (nReturnCode = Bcm30_CallProgress(Event->nChanNum,szNumber)) { printf("Error in Bcm30_CallProgress function; return code=%d\n", nReturnCode); } } //*************************************************************************** // calling exit function //*************************************************************************** void Call_Exit(struct ChanEvent *Event) { Event; // compress compiler printf(" Exit : Call_Exit\n"); } //*************************************************************************** // play "hello1.vox" entry function //*************************************************************************** void PlayMsg_Entry(struct ChanEvent *Event) { if (Play(Event->nChanNum, "hello1.vox",0)) { printf("Error playing vox file \"hello1.vox\".\n"); Exit_Entry(); } printf(" Enter: PlayMsg_Entry\n"); } //*************************************************************************** // play "hello1.vox" exit function //*************************************************************************** void PlayMsg_Exit(struct ChanEvent *Event) { close(fhVoxFile); Event; // compress compiler printf(" Exit : PlayMsg_Exit\n"); } //*************************************************************************** // //*************************************************************************** void Halt_Entry(struct ChanEvent *Event) { Event; // compress compiler printf(" Entry: Halt_Entry\n"); } //*************************************************************************** // //*************************************************************************** void Halt_Exit(struct ChanEvent *Event) { Event; // compress compiler printf(" Exit : Halt_Exit\n"); } //*************************************************************************** // exit function //*************************************************************************** void Exit_Entry() { int i; for (i=1; i <= nNumOfChan; i++) Bcm6_SetHook(i,H_ONH); Bcm3_StopSystem(); printf(" Enter: Exit_Entry\n"); printf("\n\n PROGRAM TERMINATED.\n\n"); close(fhVoxFile); exit(0); } //*************************************************************************** // Play voice file //*************************************************************************** int Play(int Chan, char *szFileName, int nTermFlag) { int nReturnCode; if (!(fhVoxFile = open(szFileName, O_BINARY | O_RDONLY))) { printf("Error in opening vox file \"hello1.vox\".\n"); Exit_Entry(); } // set up Tcb Bcm_ClearTCB(&Tcb); Tcb.FileHandle = fhVoxFile; Tcb.DTMF_Term = nTermFlag ? (BYTE)'@' : 0; Tcb.LoopDrop = 1; // start playback if (nReturnCode = Bcm13_PlayFile(Chan, &Tcb)) return(1); return(0); } //*************************************************************************** // transit states //*************************************************************************** void StateTransit(struct ChanEvent *Event) { int nCurrState, nNewState; void (*pfnEntry)(struct ChanEvent *); void (*pfnExit)(struct ChanEvent *); // find the current state of this channel nCurrState = nChanState[Event->nChanNum]; // leave current state pfnExit = LookUpTbl[nCurrState].pfnExitFunction; (*pfnExit)(Event); // execute function //find the new state of this channel nNewState = NextState[nCurrState][Event->nEventType]; nChanState[Event->nChanNum] = nNewState; // get into new state pfnEntry = LookUpTbl[nNewState].pfnEntryFunction; (*pfnEntry)(Event); // execute function } //*************************************************************************** // process events //*************************************************************************** void EventProcess(struct ChanEvent *Event) { int nKeyStroke = 0; int nReturnCode; int nEvtChan, nEvtCode, nEvtData; do { // check if any key struck, get the key if yes if (kbhit()) nKeyStroke = getch() ; // check if any event occurred nReturnCode = Bcm16_GetEvent(&nEvtChan, &nEvtCode, &nEvtData); } while ( (nReturnCode == 0) && (nKeyStroke != ESC) ); // as long as no event AND no ESC key struck, keep looping // // at this point, an event occurred OR user hit the ESC k // Event->nChanNum = nEvtChan; Event->nEventData = nEvtData; printf("------------------------------------------------\n"); printf(" Channel <%d>: Event is ", Event->nChanNum); if (nReturnCode != 0) { switch (nEvtCode) { case T_OFFH: Event->nEventType = OFHK; // off hook complete printf("\"OFHK\"\n"); break; case T_ONH: Event->nEventType = ONHK; // on hook complete printf("\"ONHK\"\n"); break; case T_EOF: Event->nEventType = ENDF; // end of file on playback printf("\"ENDF\"\n"); break; case T_LCTERM: case T_LC: Event->nEventType = LNDS; // line disconnect printf("\"LNDS\"\n"); break; case T_CATERM: printf("\"CATERM -> "); switch (nEvtData) { case CP_BUSY: // line busy printf("BUSY\"\n"); Event->nEventType = ONHK; break; case CP_NO_ANSR: // line not answer printf("NO ANSWER\"\n"); Event->nEventType = ONHK; break; case CP_NO_RESP: // line no ring printf("NO RINGBACK\"\n"); Event->nEventType = ONHK; break; case CP_INTERCEPT: // line intercepted by operator printf("INTERCEPT\"\n"); Event->nEventType = ONHK; break; case CP_CONNECT: // line connected printf("CONNECTED\"\n"); Event->nEventType = CALL; break; default: printf("Invalid call status type %d\n", nEvtData); Event->nEventType = ONHK; break; } break; default: printf("\n\nUnexpected event type %d \n", nEvtCode); Event->nEventType = LNDS; break; } } else { Event->nEventType = EXIT; printf("\"Exit\"\n"); } } //*************************************************************************** // initialize system //*************************************************************************** void Init() { int nReturnCode, nLineNum; // check if driver installed if (Bcm_GetSWIntVector()) { // stop system first Bcm3_StopSystem(); // start system if (nReturnCode = Bcm1_StartSystem(nIntLvl,SM_EVENT,0,0,&nNumOfChan)) { // cannot start system printf("Unable to start system; Return Code %d\n",nReturnCode); exit(1); } else { // start system OK printf("%d phone lines installed.\n\n",nNumOfChan); } } else { // driver not installed printf("Error: BICOM driver not installed!\n"); exit(1); } // set up every channel for (nLineNum=1; nLineNum <= nNumOfChan; nLineNum++) { // set every channel on hook nChanState[nLineNum] = ST_ONHOOK; // set Event Generation Mask Bcm7_SetEGMask(nLineNum, (C_LC // enable loop signal event queued +C_ONH // enable on hook msg +C_OFFH), // enable off hook msg 0); // dial mode // set line on hook Bcm6_SetHook(nLineNum, H_ONH); } } //*************************************************************************** // main function //*************************************************************************** void main(int argc, char *argv[]) { int i; // check if user entered interrupt level if (argc > 1) { // use the interrupt user entered sscanf(argv[1], "%d", &nIntLvl); // validate interrupt level if (nIntLvl < 2 || nIntLvl > 7) { printf("Invalid Bicom interrupt level %d\n", nIntLvl); exit(1); } } else { // use default hardware interrupt level 3 nIntLvl = INTLVL; } // print BICOM msg printf("\nBICOM (R) Multi-line Dialing Demo Program\n"); printf("Copyright (c) BICOM 1990, 1991 All rights reserved.\n\n"); // initialize system Init(); // check how many lines to dial from do { printf("Enter TOTAL NUMBER OF LINES to use...(1 - %d)... ",nNumOfChan); scanf("%d",&nLineNum); } while ((nLineNum>nNumOfChan) || (nLineNum<1)); // get phone number(s) from user for (i=1; i<=nLineNum; i++) { // clear query line printf("Enter PHONE NUMBER to dial for line %d... ",i); scanf("%s",szPhoneNum[i]); } // set the needed line(s) to onhook for (i=1; i <= nLineNum; i++) { nChanState[i] = ST_ONHOOK; Bcm6_SetHook(i,H_ONH); printf("Line %d was set to onhook\n",i); } // set the unused line(s) to HALT state for (i=nLineNum+1; i<=nNumOfChan; i++) nChanState[i] = ST_HALT; // loop forever: get event from queue, process it and go to next state while (FOREVER) { EventProcess(&Event); StateTransit(&Event); } }