40CID.EXE and COM40.SYS o Quick Install: --------------- In CONFIG.SYS, comment out COM.SYS, add COM40.SYS: ... REM device=com.sys device=com40.sys ... Reboot. At prompt, start CID40.EXE program. C>cid40 (use /h or ? for fast-tips, or read Notes below for more) As calls come in, the screen shows the CID info. Press Ctrl-C to exit and release the com port. Restart when com port is free. == 40CID.EXE requires Warp or later == o Notes: -------- To use 40CID, the COM40.SYS device driver must be installed. In CONFIG.SYS comment out DEVICE=COM.SYS and add DEVICE=COM40.SYS. Most COM.SYS options are valid for COM40.SYS (also include the appropriate path). After the change, reboot your machine. Start 40CID.EXE (this program). Optional switches are for the COM port /COMn where n=1 to 4) and the CID lead byte (/0xHH where HH is a hex byte value that matches your CID lead byte -- the defaults are 0x80 and 0x04). So, if your modem is at COM2, and your lead byte is either 0x80 or 4, you no switches -- the defaults are fine. Or, for example: C>40cid /com1 (comport) or, C>40cid -0x08 (CID lead byte) or, C>40cid -bell (bell at CID) or a combination of them. To use the com port with another program, press Ctrl-C to exit 40CID.EXE. If you exit 40CID.EXE, you should activate the modem as soon as possible so that no CIDs are lost. Up to 16 CID entries are buffered in COM40.SYS. As soon as you leave the other program, you should restart 40CID.EXE. Any buffered CIDs will be shown, up to 16 (a double beep is sounded if the buffer queue wrapped around, indicating that only the last 16 entries were saved. To check your CID lead byte, start up an ASCII terminal (e.g., ZOC or Telix) and enter: ATZ [OK] AT#CID=2 [OK] You may need to enter ATE1 to see what you type (check your modem manual). Dial the terminal's modem (or ask someone to call). The first byte sent out by a caller ID modem is the my-called 'lead byte'. I've seen this documented as being \x04 (a 'diamond' character on screen, usually), but I always get a lead byte of \x80. It may be that you won't be able to see your lead byte (e.g., if it is \x08, the backspace), so you may need to write a little ditty to read the hex values. Ask any programmer you happen to see... Your terminal program may already have this (data dump mode, etc.). If your lead byte is not \x80 or \x04, use the -0xHH switch as shown above. The output is to a Vio screen. The last 16 entries are shown. The newest is at the top, and then moving down to oldest. Initially, the first screen simply shows: Use Ctrl-C to exit program and release ComPort [40CID]_ Upon the first call, between the first and second 'RING', the CID data is sent. Depending on the origin and your service, you may not get the name, nor the number. The time is always shown. A typical call list may look like: NOT AVAILABLE (999)999-9998 12/09/95 05:01 80|xx SNEAK/NOT AVAIL (999)999-9999 12/09/95 05:00 80|xx SCUM J G (512)226-7678 12/09/95 04:58 80|xx=checksum where the most current calls are at the top, followed by earlier calls. If the name is not available, "NOT AVAILABLE" is used (note number used). If the call was made anonymously, "SNEAK/NOT AVAIL" is used (note number). The data and time follow, then the lead byte and record checksum. If the number data is unknown the following is used: UNK NUMBER DATA (999)999-9998 12/27/95 05:59 80|xx Use Ctrl-C to exit the program and release the com port. [27-Dec-1995 -- support at comp.os.os2.misc, Subject: [COM40] ...] For those interested in accessing the CID data, the API follows. This is not supported on an individual basis at this time (i.e., you are on your own). // // 40CID API // 27-Dec-95 // // Requires COM40.SYS installed as COM device. // This product is Unsupported at this time, on an individual basis. // // Copyright (C)1995 40th Floor Software // All Rights Reserved. #define IOCTL_40TH 0x40 // func code for IOCTL_ASYNC calls to com40 DD #define RETRIES_40CID 4 // retry routines up to x times #define GET_VER_CID 1 // funcNo codes #define GET_STATE_CID 2 #define SET_STATE_CID 3 #define RESET_CID 4 #define READ_QUEUE_CID 5 #define CID_RQ_LIFO -1 // read & remove newest entry in queue #define CID_RQ_FIFO 0 // read & remove oldest entry in queue #define CID_RQ_PEEKN 0 // read n-oldest entry in queue (1-entries, 1=oldest) // structures typedef struct _VERSION { ULONG status; ULONG version; ULONG queueEntries; ULONG entrySize; } VERSION; typedef VERSION *PVERSION; typedef struct _STATE { ULONG status; ULONG flags; ULONG count; UCHAR leadBytes[4]; } STATE; typedef STATE *PSTATE; typedef struct _ENTRY { ULONG status; ULONG flags; ULONG mode; UCHAR entry[64]; } ENTRY; typedef ENTRY *PENTRY; typedef struct _IOCTLPARM { UCHAR parmID[6]; SHORT funcNo; } IOCTLPARM; // ... CID40 routines ULONG GetVersion40CID (HFILE comID, PVERSION cidVerPtr); ULONG GetState40CID (HFILE comID, PSTATE statePtr); ULONG SetState40CID (HFILE comID, PSTATE statePtr); ULONG ResetActive40CID (HFILE comID, ULONG status); ULONG ReadQueue40CID (HFILE comID, PENTRY entryPtr); ///////////////////////////////////////////////////////////////////////////// // // // // 40CID routines // // // ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // ------------------------ // Get 40CID driver version // // stk: verPtr: returned version of DD, 0 if error // out: OS result code of IOCTL call, if 0 VERSION.members set always // .status = active state of driver // .version = driver version * 1000 // .queueEntries = max CID entries buffered in driver // .entrySize = max length of a single CID entry data // nts: VERSION.status returns active status (bits0-3: process stage bits) // bit0=1 in processing, and if only bit0=1 then scanning for ringStr // 1=1 ringStr matched, now scanning for lead byte // 2=1 lead byte matched, now get size byte // 3=1 size byte stored, now getting all data info, plus checksum // When all data of CID is stored, .active bits0-3 are set to 0. // // The other 40CID calls return with bit31=1 when busy, along with // the current active status (in bits0-3). It may be necessary to // force a clear of the active status bits, and that can be done at // two different levels with RESET_CID. // // HOWEVER, on next RING (second ring), .active remains in stage 0011y // since no lead byte will arrive (unless a data connect, then maybe, // and if not a matching lead byte, .active is set back to 0 and all is // okay) and so .active remains limbo'ed at .active=3. // // GET_VER_CID always returns not busy since it access R-O data. ULONG GetVersion40CID (HFILE comID, PVERSION cidVerPtr) { ULONG rc; ULONG parmLen = sizeof(IOCTLPARM); ULONG dataLen = 0; IOCTLPARM parm = {"40CID",GET_VER_CID}; rc = DosDevIOCtl(comID,IOCTL_ASYNC,IOCTL_40TH, &parm,sizeof(parm),&parmLen, cidVerPtr,sizeof(VERSION),&dataLen); return rc; } // --------------- // Get 40CID state // // stk: HFILE:comID:com port handle // PSTATE:statePtr:pointer to STATE structure to set DD to // out: OS result code of IOCTL call, if 0 STATE.members set, unless busy // nts: if the DD is busy, STATE.status=0x8000xxxx where xxxx is 1,3,5,9 ULONG GetState40CID (HFILE comID, PSTATE statePtr) { ULONG rc; ULONG parmLen = sizeof(IOCTLPARM); ULONG dataLen = 0; IOCTLPARM parm = {"40CID",GET_STATE_CID}; ULONG times,i; for (times=1; times <= 2; times++) { for (i=1; i <= RETRIES_40CID; i++) { rc = DosDevIOCtl(comID,IOCTL_ASYNC,IOCTL_40TH, &parm,sizeof(parm),&parmLen, statePtr,sizeof(STATE),&dataLen); if (rc!=0) goto ExitNow; // OS error // if busy >= 3, wait 0.75 second or so to allow processing to finish // if busy = 1, wait 2.1 seconds or so to allow for full processing rc = statePtr->status; if (rc == 0) goto ExitNow; if ((rc & 0xFF) >= 3) { DosSleep(750); // is processing (probably) } else { DosSleep(2100); // may be stuck, or processing (wait longer) rc = ResetActive40CID(comID,rc); // unstick if at <= 3 now } } rc = ResetActive40CID(comID,0x8000FFFF); } ExitNow: return rc; } // --------------- // Set 40CID state // // stk: HFILE:comID:com port handle // PSTATE:statePtr:pointer to STATE structure to set DD to // out: OS result code of IOCTL call, if 0 STATE.active set // nts: The DD state cannot be set if the current active state is busy. // Currently, only the leadBytes can be changed. // < Beta levels require .flags=0x19771959 on entry to activate 40CID > ULONG SetState40CID (HFILE comID, PSTATE statePtr) { ULONG rc; ULONG parmLen = sizeof(IOCTLPARM); ULONG dataLen = 0; IOCTLPARM parm = {"40CID",SET_STATE_CID}; ULONG times,i; for (times=1; times <= 2; times++) { for (i=1; i <= RETRIES_40CID; i++) { rc = DosDevIOCtl(comID,IOCTL_ASYNC,IOCTL_40TH, &parm,sizeof(parm),&parmLen, statePtr,sizeof(STATE),&dataLen); if (rc!=0) goto ExitNow; // OS error // if busy >= 3, wait 0.75 second or so to allow processing to finish // if busy = 1, wait 2.1 seconds or so to allow for full processing rc = statePtr->status; if (rc == 0) goto ExitNow; if ((rc & 0xFF) >= 3) { DosSleep(750); // is processing (probably) } else { DosSleep(2100); // may be stuck, or processing (wait longer) rc = ResetActive40CID(comID,rc); // unstick if at <= 3 now } } rc = ResetActive40CID(comID,0x8000FFFF); } ExitNow: return rc; } // ----------------------- // Reset 40CID active flag // // stk: HFILE:comID:com port handle // ULONG:status:status to use (0x8000xxxx, xxxx=1, or 3, or FFFF) // out: OS result code of IOCTL call, if 0 STATE.active reset if <= 3 // nts: // This call typically used after a routine errors out with a busy, // and a wait of at least 1/10th second has transpired, but no more // than 1 second (or so). If more than 1 second, then it's possible // that this may clear a new CID call just starting. When called, if // the current active state is <=3, the active state is reset (so call // this routine only after waiting 0.1 to 1 second after the first busy). // If busy still, and active > 3, then that busy state is returned. You // may force a reset by calling with status=0x8000FFFF. // // state.status is typically set to the busy error value returned from the // original call that indicated the DD was busy (0x8000xxxx, xxxx=1 or 3). // This after waiting appoximately 1/10th to 1 second from the busy // indication, so that any real processing can complete normally. If // busy is still indicated (as returned from this call), then you may // force the DD to become unbusy by set statePtr->status=0x8000FFFF. // This should be a last resort -- only if you believe the DD has hung // up on bogus caller ID data. One way to determine this is to // repeatedly call this routine, once a second, for 5 seconds or so, // checking the return status. If always the same (it will be greater // than 0x80000003) you should go ahead and force a reset by setting // state.status=0x8000FFFF. This clears the active state at the driver // and permits calls to proceed without the 'busy' error returned. ULONG ResetActive40CID (HFILE comID, ULONG status) { ULONG rc; ULONG parmLen = sizeof(IOCTLPARM); ULONG dataLen = 0; IOCTLPARM parm = {"40CID",RESET_CID}; STATE state; state.status = status; // reset active flag (possibly by force) rc = DosDevIOCtl(comID,IOCTL_ASYNC,IOCTL_40TH, &parm,sizeof(parm),&parmLen, &state,sizeof(STATE),&dataLen); if (rc==0) rc = state.status; return rc; } // -------------- // Read CID Queue // // stk: HFILE:comID:com port handle // PENTRY:entryPtr:pointer to ENTRY // out: OS result code of IOCTL call // nts: ULONG ReadQueue40CID (HFILE comID, PENTRY entryPtr) { ULONG rc; ULONG parmLen = sizeof(IOCTLPARM); ULONG dataLen = 0; IOCTLPARM parm = {"40CID",READ_QUEUE_CID}; ULONG times,i; for (times=1; times <= 2; times++) { for (i=1; i <= RETRIES_40CID; i++) { rc = DosDevIOCtl(comID,IOCTL_ASYNC,IOCTL_40TH, &parm,sizeof(parm),&parmLen, entryPtr,sizeof(ENTRY),&dataLen); if (rc!=0) goto ExitNow; // OS error // if busy >= 3, wait 0.75 second or so to allow processing to finish // if busy = 1, wait 2.1 seconds or so to allow for full processing rc = entryPtr->status; if (rc == 0) goto ExitNow; // DosBeep(1000,100); if ((rc & 0xFF) >= 3) { DosSleep(750); // is processing (probably) } else { DosSleep(2100); // may be stuck, or processing (wait longer) rc = ResetActive40CID(comID,rc); // unstick if at <= 3 now } } rc = ResetActive40CID(comID,0x8000FFFF); DosBeep(60,100); } ExitNow: return rc; } // This is unsupported at this time -- you are on your own, programmer.