Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
ADSP.c
/***************************************************************** |
Program: < ADSP Chat > |
File: < adsp.c > |
Written by Pete Helm, Scott Kuechle |
of <Apple Macintosh Developer Technical Support> |
modified by Scott Kuechle |
10/92 SRK Converted from Pascal to C |
8/94 SRK Modified to use a queue of parameter |
blocks. |
Copyright © 1992, 1994 Apple Computer, Inc. |
All rights reserved. |
*****************************************************************/ |
/*****************************************************************/ |
/* I N C L U D E S |
/*****************************************************************/ |
#include "ADSP Chat.h" |
/******************************************************************** |
/* G L O B A L V A R I A B L E D E C L A R A T I O N S |
/********************************************************************/ |
char myLocalSocket; |
Ptr receiveQBuffer; |
Ptr sendQBuffer; |
Ptr attnBuffer; |
Ptr outAttnBuff; |
Ptr receiveBuffer; |
Ptr outgoingDataBuffer; |
TRCCB gMyCCB; /* our ccb */ |
short gADSPDrvrRefNum; /* adsp driver reference number */ |
short gCCBRefNum; /* ccb reference number returned by adsp on a dspInit */ |
Boolean gJustConnected; /* dspOpen ocRequest was successfully accepted */ |
QHdr gAvailQueue; |
QHdr gDoneQueue; |
QHdr gReadQueue; |
/*****************************************************************/ |
/* |
/* E X T E R N A L S |
/* |
/*****************************************************************/ |
extern void removeMyName(); |
extern Boolean registerMyName(); |
extern void ShowError(short index); |
extern void DisplayCurrentStatus(Ptr displayStr); |
extern void HiliteConnectButton (short mode); |
extern void Exit(short message); |
extern Str255 gZoneString, gObjStr, gTypeStr; |
extern Str32 myName; |
extern DialogPtr myDialog; |
extern QHdr freeQHdr,saveErrorQHdr; |
extern AddrBlock ourNetworkAddress; |
extern void CopyPstr(Ptr pSource, Ptr pDest); |
extern void PStrCat(Ptr sourceStr, Ptr destinationStr); |
extern void zeroOutStrings(); |
extern void PreCompletion(); |
#pragma segment adsp |
// ***************************************************************** |
// * doADSPinit |
// * |
// * calls dspInit, saves the socket and ccb refnum returned |
// ***************************************************************** |
Boolean doADSPinit(unsigned char *localSocket, |
short *ccbRefNum, |
TPCCB ccbPtr) |
{ |
TRinitParams *initParmsPtr; |
DSPParamBlock dspPB; |
/* allocate connection end */ |
dspPB.ioCRefNum = gADSPDrvrRefNum; |
dspPB.csCode = dspInit; |
initParmsPtr = &dspPB.u.initParams; |
initParmsPtr->ccbPtr = ccbPtr; |
/* poll in main event loop instead of using user routine */ |
initParmsPtr->userRoutine = NULL; |
initParmsPtr->sendQSize = Qsize; |
initParmsPtr->sendQueue = sendQBuffer; |
initParmsPtr->recvQSize = Qsize; |
initParmsPtr->recvQueue = receiveQBuffer; |
initParmsPtr->attnPtr = attnBuffer; |
initParmsPtr->localSocket = 0; /* dynamically allocate a socket for us */ |
if (PBControl((ParmBlkPtr)&dspPB, false) != noErr) |
Exit(DrvrErr); |
else if ( dspPB.ioResult == noErr) /* any errors? */ |
{ |
/* save socket returned to us by ADSP */ |
*localSocket = initParmsPtr->localSocket; |
/* save ccb reference number returned to us by ADSP */ |
*ccbRefNum = dspPB.ccbRefNum; |
return true; |
} |
else /* got an error on the dspInit */ |
{ |
*ccbRefNum = 0; |
ShowError(dspInitErr); |
return false; |
} |
} |
// ***************************************************************** |
// * initializeADSP |
// * |
// * opens the adsp driver, allocates memory for our adsp buffers |
// * then issues a passive open call |
// ***************************************************************** |
void initializeADSP() |
{ |
/* set up the ADSP connection end. */ |
gJustConnected = false; |
gCCBRefNum = 0; |
changeConnectButtonState(); |
/* open the ADSP driver here - we need the reference number |
for all ADSP calls */ |
if (OpenDriver("\p.DSP", &gADSPDrvrRefNum) != noErr) |
Exit(atalkErr); |
if (InitQueues() == noErr) |
{ |
/* allocate memory for our buffers and then |
issue a passive open */ |
if (setUpADSPbuffers() == true) |
{ |
/* issue a passive open */ |
if (WaitForConnectionRequest() != true) |
{ |
/* oops! got an error so deallocate our buffers */ |
removeADSPBuffers(); |
Exit(memErr); |
} |
} |
else |
Exit(noMemErr); |
} |
else |
Exit(memErr); |
} |
// ***************************************************************** |
// * SetOurCompletionRoutine |
// * |
// * Sets the "real" completion routine for our async. calls |
// ***************************************************************** |
void SetOurCompletionRoutine(ProcPtr procPtr, |
DSPPBPtr dspPBPtr) |
{ |
Ptr p; |
myDSPParamBlockPtr myDSPPBPtr; |
p = (Ptr)dspPBPtr; |
/* the "ourCompletion" field is offset |
8 bytes above the DSPParmBlock in |
our definition */ |
myDSPPBPtr = (myDSPParamBlockPtr)(p - 8); |
myDSPPBPtr->ourCompletion = procPtr; |
} |
// ***************************************************************** |
// * GetQElement |
// * |
// * retrieve a queue element from the specified queue |
// ***************************************************************** |
DSPPBPtr GetQElement(QHdrPtr qHdrPtr) |
{ |
OSErr err; |
QElemPtr qElemPtr; |
CheckDoneQueue(); |
qElemPtr = qHdrPtr->qHead; |
if (qElemPtr != NULL) |
{ |
err = Dequeue((QElemPtr)qElemPtr,qHdrPtr); |
if (err != noErr) |
{ |
return NULL; |
} |
else |
{ |
return (DSPPBPtr)(qElemPtr); |
} |
} |
else |
return NULL; |
} |
// ***************************************************************** |
// * InitQueues |
// * |
// * initialize our "Available" , "Done" and "Read" queues |
// ***************************************************************** |
OSErr InitQueues() |
{ |
short i; |
OSErr err; |
long myA5; |
myDSPParamBlockPtr myQElem; |
gAvailQueue.qHead = NULL; |
gAvailQueue.qTail = NULL; |
gDoneQueue.qHead = NULL; |
gDoneQueue.qTail = NULL; |
gReadQueue.qHead = NULL; |
gReadQueue.qTail = NULL; |
err = noErr; |
myA5 = *(long *)CurrentA5; |
for (i=0; (i < maxQElements) || (err != noErr); ++i) |
{ |
myQElem = (myDSPParamBlockPtr)NewPtr(sizeof(myDSPParamBlock)); |
if (myQElem != NULL) |
{ |
myQElem->myA5 = myA5; |
myQElem->u.ioCompletion = (ProcPtr)&PreCompletion; |
Enqueue((QElemPtr)&myQElem->u,&gAvailQueue); |
} |
else |
{ |
err = MemError(); |
} |
} |
return err; |
} |
// ***************************************************************** |
// * setUpADSPbuffers |
// * |
// * allocates memory for our adsp buffers |
// ***************************************************************** |
Boolean setUpADSPbuffers() |
{ |
receiveQBuffer = NewPtr(Qsize); |
if ( receiveQBuffer == nil) return false; |
sendQBuffer = NewPtr(Qsize); |
if ( sendQBuffer == nil) return false; |
attnBuffer = NewPtr(attnBufSize); |
if ( attnBuffer == nil) return false; |
outAttnBuff = NewPtr(attnBufSize); |
if ( outAttnBuff == nil) return false; |
receiveBuffer = NewPtr(attnBufSize); |
if ( receiveBuffer == nil) return false; |
outgoingDataBuffer = NewPtr(Qsize); |
if ( outgoingDataBuffer == nil) return false; |
return true; |
} |
// ***************************************************************** |
// * changeConnectButtonState |
// * |
// * sets the correct state for our connect button |
// ***************************************************************** |
void changeConnectButtonState() |
{ |
/* this procedure reflects the state of our connection in the control */ |
Rect r; |
short kind; |
Handle h; |
GetDItem(myDialog, kConnectButtonID, &kind, &h, &r); |
if ( (gCCBRefNum == 0) || |
((gCCBRefNum != 0) && (gMyCCB.state == sClosed)) ) |
SetCTitle((ControlHandle)h, "\pConnect"); |
else |
{ |
SetCTitle((ControlHandle)h, "\pDisconnect"); |
HiliteConnectButton(0); |
} |
} |
// ***************************************************************** |
// * DisplayTime |
// * |
// * this procedure responds to an attention message from the remote |
// * Mac which contains the time of that Mac. Silly yes, but it does |
// * show how to use the attnMsg stuff. |
// ***************************************************************** |
void DisplayTime() |
{ |
Rect r; |
short kind; |
Handle h; |
long dateTime; |
Str255 str, str2; |
GetDItem(myDialog, kRemoteMacsTimeID, &kind, &h, &r); |
GetIText(h, str2); |
BlockMove(attnBuffer, &dateTime, 4); |
IUTimeString(dateTime, true, str); |
/* this just checks to see that we're not already displaying this time already */ |
/* flashing text sucks... so sayeth me */ |
if (IUCompString(str,str2) != 0) |
SetIText(h, str); |
} |
// ***************************************************************** |
// * DisplayTheirName |
// * |
// * this procedure responds to an attention message from the remote |
// * Mac which contains the remote Mac's Chooser name. |
// ***************************************************************** |
void DisplayTheirName() |
{ |
Rect r; |
short kind; |
Handle h; |
Str255 str; |
GetDItem(myDialog, kRemoteMacsNameID, &kind, &h, &r); |
BlockMove(attnBuffer, &str, 255); |
SetIText(h, str); |
} |
// ***************************************************************** |
// * DisplayIncomingText |
// * |
// * this procedure takes the text written to our receive buffer from |
// * the remote Mac and displays the text in a dialog item |
// ***************************************************************** |
void DisplayIncomingText(DSPPBPtr dspPBPtr) |
{ |
Rect r; |
short kind; |
Handle h; |
Str255 str; |
GetDItem(myDialog, kIncomingTextID, &kind, &h, &r); |
BlockMove(dspPBPtr->u.ioParams.dataPtr, (Ptr)(&str[1]), 255); |
str[0] = (char)dspPBPtr->u.ioParams.actCount; |
SetIText(h, &str); |
} |
// ***************************************************************** |
// * removeADSPBuffers |
// * |
// * this procedure deallocates the memory for our adsp buffers. |
// ***************************************************************** |
void removeADSPBuffers() |
{ |
if (receiveQBuffer != NULL) |
DisposPtr(receiveQBuffer); |
if (sendQBuffer != NULL) |
DisposPtr(sendQBuffer); |
if (attnBuffer != NULL) |
DisposPtr(attnBuffer); |
if (outAttnBuff != NULL) |
DisposPtr(outAttnBuff); |
if (receiveBuffer != NULL) |
DisposPtr(receiveBuffer); |
if (outgoingDataBuffer != NULL) |
DisposPtr(outgoingDataBuffer); |
} |
// ***************************************************************** |
// * CloseTheConnection |
// * |
// * calls dspClose to close the connection end. |
// ***************************************************************** |
void CloseTheConnection(short ccbRefNum) |
{ |
DSPParamBlock pb; |
pb.ioCRefNum = gADSPDrvrRefNum; |
pb.csCode = dspClose; |
pb.ccbRefNum = ccbRefNum; |
pb.u.closeParams.abort = 1; /* non zero value aborts any outstanding calls */ |
if (PBControl((ParmBlkPtr)&pb, false) != noErr) |
Exit(DrvrErr); |
} |
// ***************************************************************** |
// * removeConnectionEnd |
// * |
// * calls dspRemove to eliminate the connection end. |
// ***************************************************************** |
void removeConnectionEnd(short ccbRefNum) |
{ |
DSPParamBlock pb; |
pb.ioCRefNum = gADSPDrvrRefNum; |
pb.csCode = dspRemove; |
pb.ccbRefNum = ccbRefNum; |
pb.u.closeParams.abort = 1; /* non zero value aborts any outstanding calls */ |
if (PBControl((ParmBlkPtr)&pb, false) != noErr) |
Exit(DrvrErr); |
if (pb.ioResult != noErr) |
ShowError(dspRemoveErr); |
} |
// ***************************************************************** |
// * WaitForConnectionRequest |
// * |
// * calls dspInit to establish a connection end. Then registers |
// * our name on the net and does a passive open. |
// ***************************************************************** |
Boolean WaitForConnectionRequest() |
{ |
DSPPBPtr dspPBPtr; |
/* first issue a dspInit */ |
if (doADSPinit(&myLocalSocket, |
&gCCBRefNum, |
&gMyCCB) == true) |
{ |
/* save our socket for comparison purposes later */ |
ourNetworkAddress.aSocket = myLocalSocket; |
/* now register our nbp name with type "moof" */ |
if (registerMyName() == true) |
{ |
/* get QElement for the dspInit call */ |
dspPBPtr = GetQElement(&gAvailQueue); |
if (dspPBPtr != NULL) |
{ |
/* do a passive open, waiting for open requests */ |
DoPassiveOpen(dspPBPtr, |
gCCBRefNum); |
return true; |
} |
} |
else /* we got an error! */ |
{ /* remove connection end with dspRemove */ |
removeConnectionEnd(gCCBRefNum); |
/* de-allocate memory we got for our buffers */ |
removeADSPBuffers(); |
} |
} |
return false; |
} |
// ***************************************************************** |
// * CloseConnection |
// * |
// * calls dspRemove to eliminate the connection end. Then removes |
// * our nbp name from the net and re-issues a passive open. |
// ***************************************************************** |
void CloseConnection() |
{ |
/* do a dspRemove to close the connection end */ |
removeConnectionEnd(gCCBRefNum); |
/* remove our nbp name "moof" */ |
removeMyName(); |
changeConnectButtonState(); |
zeroOutStrings(); |
/* at this point, we have closed the connection so let's issue |
an asynchronous passive open. This call will complete whenever |
we receive an open connection request from another machine. */ |
WaitForConnectionRequest(); |
} |
// ***************************************************************** |
// * sendAttnMsgCompRoutine |
// * |
// * when our send attention message call completes this procedure |
// * will get called. |
// ***************************************************************** |
pascal void sendAttnMsgCompRoutine(DSPPBPtr dspPBPtr) |
{ |
if (dspPBPtr->ioResult == noErr) |
/* place parameter block back into the "Available" queue */ |
Enqueue((QElemPtr)dspPBPtr,&gAvailQueue); |
else /* some kind of error was returned */ |
/* place parameter block back into the "Done" queue */ |
Enqueue((QElemPtr)dspPBPtr,&gDoneQueue); |
} |
// ***************************************************************** |
// * sendAttnMsg |
// * |
// * this is a generic attention message sending routine. all |
// * attention messages are sent async using a shared buffer. |
// * the message code and the size of the message are passed to |
// * this proc. |
// ***************************************************************** |
void sendAttnMsg(DSPPBPtr dspPBPtr, |
short buffSize, |
Ptr attnData, |
short msg, |
short ccbRefNum) |
{ |
TRattnParams *attnParmsPtr; |
/* this is a generic attention message sending routine. all attention messages are sent*/ |
/* async using a shared buffer. the message code and the size of the message are passed to */ |
/* this proc.*/ |
SetOurCompletionRoutine((ProcPtr)&sendAttnMsgCompRoutine, |
dspPBPtr); |
dspPBPtr->ioCRefNum = gADSPDrvrRefNum; |
dspPBPtr->csCode = dspAttention; |
dspPBPtr->ccbRefNum = ccbRefNum; |
attnParmsPtr = &dspPBPtr->u.attnParams; |
attnParmsPtr->attnCode = (unsigned short)msg; |
attnParmsPtr->attnSize = buffSize; |
attnParmsPtr->attnData = attnData; |
attnParmsPtr->attnInterval = 10; |
if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr) |
Exit(DrvrErr); |
} |
// ***************************************************************** |
// * OpenPassiveCompletionRtn |
// * |
// * when our passive open call completes this procedure |
// * will get called. |
// ***************************************************************** |
pascal void OpenPassiveCompletionRtn(DSPPBPtr dspPBPtr) |
{ |
if (dspPBPtr->ioResult == noErr) |
{ |
gJustConnected = true; |
/* issue a read so we can catch |
any messages sent to us */ |
readIncoming(dspPBPtr, |
gCCBRefNum); |
} |
else |
/* place parameter block back into the "Done" queue */ |
Enqueue((QElemPtr)dspPBPtr,&gDoneQueue); |
} |
// ***************************************************************** |
// * DoPassiveOpen |
// * |
// * issues an asynchronous passive open call. Any machine wishing |
// * to connect to us must only send us an open request (dspOpen, |
// * ocRequest mode). Once we get a request, our completion routine |
// * is called and the connection is established. |
// ***************************************************************** |
void DoPassiveOpen(DSPPBPtr dspPBPtr, |
short ccbRefNum) |
{ |
AddrBlock filterAddress; |
TRopenParams *openPBPtr; |
/* send an open request */ |
SetOurCompletionRoutine((ProcPtr)&OpenPassiveCompletionRtn, |
dspPBPtr); |
dspPBPtr->ioCRefNum = gADSPDrvrRefNum; |
dspPBPtr->csCode = dspOpen; |
dspPBPtr->ccbRefNum = ccbRefNum; /* refNum of connection end */ |
/* accept open requests from anyone */ |
filterAddress.aNet = 0; |
filterAddress.aNode = 0; |
filterAddress.aSocket = 0; |
openPBPtr = &dspPBPtr->u.openParams; |
openPBPtr->filterAddress = filterAddress; |
openPBPtr->ocMode = ocPassive; |
openPBPtr->ocInterval = 0; /* use default value of 6 (1 second) */ |
openPBPtr->ocMaximum = 255; /* retransmit indefinitely */ |
if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr) |
Exit(dspOpenErr); |
} |
// ***************************************************************** |
// * adspOpenRqstCompletionRtn |
// * |
// * when our open request call completes this procedure |
// * will get called. If we dont get back any errors then the |
// * connection is established with the target. |
// ***************************************************************** |
pascal void adspOpenRqstCompletionRtn(DSPPBPtr dspPBPtr) |
{ |
if (dspPBPtr->ioResult == noErr) |
{ |
gJustConnected = true; |
/* issue a read so we can catch |
any messages sent to us */ |
readIncoming(dspPBPtr, |
gCCBRefNum); |
} |
else |
/* place parameter block back into the "Done" queue */ |
Enqueue((QElemPtr)dspPBPtr,&gDoneQueue); |
} |
// ***************************************************************** |
// * sendAnOpenConnReq |
// * |
// * issues an open request call to the target. |
// ***************************************************************** |
void sendAnOpenConnReq (DSPPBPtr dspPBPtr, |
AddrBlock theirAddress, |
short ccbRefNum) |
{ |
AddrBlock filterAddress; |
TRopenParams *openPBPtr; |
/* make a connection only with the selected target */ |
filterAddress = theirAddress; |
/* send an open request */ |
SetOurCompletionRoutine((ProcPtr)&adspOpenRqstCompletionRtn, |
dspPBPtr); |
dspPBPtr->ioCRefNum = gADSPDrvrRefNum; |
dspPBPtr->csCode = dspOpen; |
dspPBPtr->ccbRefNum = ccbRefNum; |
/* refNum of connection end */ |
openPBPtr = &dspPBPtr->u.openParams; |
openPBPtr->remoteAddress = theirAddress; |
openPBPtr->filterAddress = filterAddress; |
openPBPtr->ocMode = ocRequest; |
openPBPtr->ocInterval = 6; |
openPBPtr->ocMaximum = 5; |
if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr) |
Exit(dspOpenErr); |
} |
// ***************************************************************** |
// * connectToPeer |
// * |
// * first checks to see if the target is still there. Next, it |
// * issues an open request to the target (but it first closes |
// * the connection end which forces any prior passive open calls to |
// * complete). |
// ***************************************************************** |
void connectToPeer() |
{ |
NBPparms *nbpParms; |
MPPParamBlock pbLKP; |
char returnBuffer[kLookupBufSize]; |
EntityName abEntity; |
AddrBlock address; |
NamesTableEntry namesTableEntry; |
DSPPBPtr dspPBPtr; |
if (gMyCCB.state == sClosed || |
gMyCCB.state == sPassive) |
{ |
NBPSetEntity((Ptr)&namesTableEntry, gObjStr, gTypeStr, gZoneString); |
nbpParms = &pbLKP.NBP; |
nbpParms->interval = 3; |
nbpParms->count = 3; |
nbpParms->NBPPtrs.entityPtr = (Ptr)&namesTableEntry; |
nbpParms->parm.Lookup.retBuffSize = kLookupBufSize; |
nbpParms->parm.Lookup.retBuffPtr = &returnBuffer; |
nbpParms->parm.Lookup.maxToGet = 1; |
/* see if the target still exists */ |
if (PLookupName(&pbLKP, false) == noErr) |
{ |
if ( nbpParms->parm.Lookup.numGotten > 0) |
{ |
/* look for the target in our return buffer */ |
if (NBPExtract(returnBuffer, |
nbpParms->parm.Lookup.numGotten, |
1, |
&abEntity, |
&address) == noErr) |
{ |
/* if a passive open has been issued, we must first close the connection end (which |
will cancel the open) before we can issue an open request to the target */ |
if (gMyCCB.state == sPassive) |
{ |
CloseTheConnection(gCCBRefNum); |
} |
dspPBPtr = GetQElement(&gAvailQueue); |
if (dspPBPtr != NULL) |
{ |
/* issue an open request to the target */ |
sendAnOpenConnReq(dspPBPtr, |
address, |
gCCBRefNum); |
} |
} |
} |
else /* target not found */ |
ShowError(noTargetErr); |
} |
} |
else /* disconnect */ |
{ |
CloseConnection(); |
} |
} |
// ***************************************************************** |
// * readIncomingComp |
// * |
// * this routine is called when our asynchronous dspRead call |
// * completes. |
// ***************************************************************** |
pascal void readIncomingComp(DSPPBPtr dspPBPtr) |
{ |
if (dspPBPtr->ioResult == noErr) |
{ |
/* place parameter block back into the "Read" queue */ |
Enqueue((QElemPtr)dspPBPtr,&gReadQueue); |
} |
else /* error occurred */ |
{ |
/* place parameter block back into the "Done" queue */ |
Enqueue((QElemPtr)dspPBPtr,&gDoneQueue); |
} |
} |
// ***************************************************************** |
// * readIncoming |
// * |
// * issues an asynchronous dspRead to read any incoming messages |
// ***************************************************************** |
void readIncoming(DSPPBPtr dspPBPtr, |
short ccbRefNum) |
{ |
TRioParams *ioPBPtr; |
SetOurCompletionRoutine((ProcPtr)&readIncomingComp, |
dspPBPtr); |
dspPBPtr->ioCRefNum = gADSPDrvrRefNum; |
dspPBPtr->csCode = dspRead; |
dspPBPtr->ccbRefNum = ccbRefNum; |
ioPBPtr = &dspPBPtr->u.ioParams; |
ioPBPtr->reqCount = Qsize; |
ioPBPtr->dataPtr = receiveBuffer; |
if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr) |
Exit(DrvrErr); |
} |
// ***************************************************************** |
// * writeComp |
// * |
// * when our asynchronous dspWrite completes this routine will get |
// * called. |
// ***************************************************************** |
pascal void writeComp(DSPPBPtr dspPBPtr) |
{ |
/* place parameter block back into the "Done" queue */ |
Enqueue((QElemPtr)dspPBPtr,&gDoneQueue); |
} |
// ***************************************************************** |
// * writeOutgoing |
// * |
// * issues an asynchronous dspWrite which sends any text that has |
// * been entered to the target machine. |
// ***************************************************************** |
void writeOutgoing(DSPPBPtr dspPBPtr, |
short ccbRefNum, |
Ptr dataPtr, |
short reqCount) |
{ |
TRioParams *ioPBPtr; |
SetOurCompletionRoutine((ProcPtr)&writeComp, |
dspPBPtr); |
dspPBPtr->ioCRefNum = gADSPDrvrRefNum; |
dspPBPtr->csCode = dspWrite; |
dspPBPtr->ccbRefNum = ccbRefNum; |
ioPBPtr = &dspPBPtr->u.ioParams; |
ioPBPtr->reqCount = reqCount; |
ioPBPtr->dataPtr = dataPtr; |
ioPBPtr->eom = 1; |
ioPBPtr->flush = 1; |
if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr) |
Exit(DrvrErr); |
} |
// ***************************************************************** |
// * sendTime |
// * |
// * this procedure sends an attention message packet with our |
// * time to the remote Mac. |
// ***************************************************************** |
void sendTime() |
{ |
unsigned long secs; |
DSPPBPtr dspPBPtr; |
GetDateTime(&secs); |
BlockMove(&secs, outAttnBuff, 4); |
dspPBPtr = GetQElement(&gAvailQueue); |
if (dspPBPtr != NULL) |
{ |
sendAttnMsg(dspPBPtr, |
4, |
outAttnBuff, |
kDisplayTime, |
gCCBRefNum); |
} |
} |
// ***************************************************************** |
// * sendMyName |
// * |
// * this procedure sends an attention message packet with our |
// * Chooser name to the remote Mac. |
// ***************************************************************** |
void sendMyName() |
{ |
DSPPBPtr dspPBPtr; |
Str255 str; |
BlockMove(myName,str,myName[0]+1); |
BlockMove(&str, outAttnBuff, 256); |
dspPBPtr = GetQElement(&gAvailQueue); |
if (dspPBPtr != NULL) |
{ |
sendAttnMsg(dspPBPtr, |
256, |
outAttnBuff, |
kDisplayTheirName, |
gCCBRefNum); |
} |
} |
// ***************************************************************** |
// * signalConnect |
// * |
// * after our passive open call has completed with an open request, |
// * or after an open request that we have issued to the target has |
// * completed, we set a flag which causes this routine to get called. |
// * This routine then sends the Chooser name of our machine to the |
// * target. |
// ***************************************************************** |
void signalConnect() |
{ |
SysBeep(1); |
changeConnectButtonState(); |
/* send our machine's name to the other end */ |
sendMyName(); |
/*Change selection to outgoing text TERecord */ |
SelIText(myDialog, kOutgoingTextID, 0, 32767); |
} |
// ***************************************************************** |
// * checkAttnMsgs |
// * |
// * If an attention message has been sent, we process it here. |
// ***************************************************************** |
void checkAttnMsgs() |
{ |
switch(gMyCCB.attnCode) |
{ |
case kDisplayTime: |
DisplayTime(); |
break; |
case kDisplayTheirName: |
DisplayTheirName(); |
break; |
} |
} |
// ***************************************************************** |
// * DoConnectionEvents |
// * |
// * This routine checks for unsolicited connection events and |
// * processes them accordingly. |
// ***************************************************************** |
void DoConnectionEvents() |
{ |
short state; |
Byte flags; |
state = gMyCCB.state; |
flags = gMyCCB.userFlags; |
if (state == sOpen) |
DisplayCurrentStatus("\pConnection established."); |
else if (state == sClosed) |
DisplayCurrentStatus("\pNot currently connected."); |
else if (state == sPassive) |
DisplayCurrentStatus("\pWaiting to accept connection."); |
if (flags & eAttention) |
{ |
checkAttnMsgs(); |
/* we must clear the bit after we have used it or we wont |
get any more messages */ |
BitClr(&gMyCCB.userFlags,2); |
} |
else if (flags & eClosed) |
{ |
DisplayCurrentStatus("\pConnection was closed."); |
/* we must clear the bit after we have used it or we wont |
get any more messages */ |
BitClr(&gMyCCB.userFlags,0); |
CloseConnection(); |
} |
/* after two minutes or so if the connection has broken we'll be notified by */ |
/* the .DSP driver with an eTearDown message */ |
else if (flags & eTearDown) |
{ |
SysBeep(2); |
SysBeep(2); |
DisplayCurrentStatus("\pConnection torn down."); |
/* we must clear the bit after we have used it or we wont |
get any more messages */ |
BitClr(&gMyCCB.userFlags,1); |
CloseConnection(); |
} |
} |
// ***************************************************************** |
// * CheckDoneQueue |
// * |
// * This routine looks through the "Done" queue for calls that |
// * have completed and reports any errors. |
// ***************************************************************** |
void CheckDoneQueue() |
{ |
QElemPtr qElemPtr; |
DSPPBPtr dspPBPtr; |
OSErr err; |
/* have any Writes completed? */ |
if (gDoneQueue.qHead != nil) |
{ |
qElemPtr = gDoneQueue.qHead; |
err = Dequeue((QElemPtr)qElemPtr,&gDoneQueue); |
if (err == noErr) |
{ |
dspPBPtr = (DSPPBPtr)qElemPtr; |
/* were there any errors on this particular call? */ |
if (dspPBPtr->ioResult != noErr) |
{ |
ShowADSPError(dspPBPtr); |
} |
/* place queue element back into the "available" queue */ |
Enqueue((QElemPtr)qElemPtr,&gAvailQueue); |
} |
} |
} |
// ***************************************************************** |
// * CheckCompletedReads |
// * |
// * This routine looks through the "Read" queue for calls that |
// * have completed, displays the text that was read and re-issues |
// * another asynchronous read call. |
// ***************************************************************** |
void CheckCompletedReads() |
{ |
QElemPtr qElemPtr; |
DSPPBPtr dspPBPtr; |
OSErr err; |
/* have any reads completed? */ |
if (gReadQueue.qHead != nil) |
{ |
qElemPtr = gReadQueue.qHead; |
err = Dequeue((QElemPtr)qElemPtr,&gReadQueue); |
if (err == noErr) |
{ |
dspPBPtr = (DSPPBPtr)qElemPtr; |
/* were there any errors on this particular read call? */ |
if (dspPBPtr->ioResult == noErr) |
{ |
/* show the text */ |
DisplayIncomingText(dspPBPtr); |
} |
else |
{ |
ShowADSPError(dspPBPtr); |
} |
/* go ahead and issue another asynchronous read */ |
readIncoming(dspPBPtr, |
gCCBRefNum); |
} |
} |
} |
// ***************************************************************** |
// * ADSPLoop |
// * |
// * This is called from our idle procedure in our main event |
// * loop. If a connection is made, we learn about it here. If we |
// * do detect that a connection has been made, we check for |
// * connection events and issue read and write calls here. |
// ***************************************************************** |
void ADSPLoop() |
{ |
/* check to see if our passive open completed with an open |
request from another machine OR if an open request that |
we issued to the target has completed */ |
if (gJustConnected == true) |
{ |
/* reset our flag */ |
gJustConnected = false; |
/* set status message to indicate we have a connection */ |
signalConnect(); |
} |
/* check for connection events */ |
DoConnectionEvents(); |
if (gMyCCB.state != sClosed) |
{ |
/* have any read calls completed? */ |
CheckCompletedReads(); |
/* check for all other calls that have completed */ |
CheckDoneQueue(); |
} |
/* do we currently have a connection? */ |
if (gMyCCB.state == sOpen) |
{ |
/* we have a connection so send our clock time |
to the other machine */ |
sendTime(); |
} |
} |
// ***************************************************************** |
// * SetUpADSPError |
// * |
// * sets our error string for the desired error code |
// ***************************************************************** |
void SetUpADSPError(OSErr err, StringPtr displayStr) |
{ |
switch (err) |
{ |
case errAborted: |
PStrCat("\pControl call was aborted.",(Ptr)displayStr); |
break; |
case errState: |
PStrCat("\pBad connection state for this operation.",(Ptr)displayStr); |
break; |
case errOpening: |
PStrCat("\pOpen connection request failed.",(Ptr)displayStr); |
break; |
case errOpenDenied: |
PStrCat("\pOpen connection request was denied.",(Ptr)displayStr); |
break; |
default: |
NumToString(err,(Ptr)displayStr); |
} |
} |
// ***************************************************************** |
// * ShowADSPError |
// * |
// * If one of our asynchronous adsp calls returned an error, the |
// * parameter block gets stuffed into an error OSQueue by the completion |
// * routine. This error queue is checked periodically by this routine. |
// * If the queue is not empty, then we got an error so we display it here |
// * and do any processing of the error that we want. |
// ***************************************************************** |
void ShowADSPError(DSPPBPtr dspPBPtr) |
{ |
short itemHit; |
Str255 displayStr,theError; |
displayStr[0] = 0; |
/* Use cscode field of the parameter block |
to see which call this error is for*/ |
switch (dspPBPtr->csCode) |
{ |
case dspRead: |
/* We'll ignore the "errState" error for now, |
since you'll get this when you close a |
connection (and we don't really need to |
report it in that case) */ |
if (dspPBPtr->ioResult != errState) |
{ |
CopyPstr("\pdspRead error. ",&displayStr); |
SetUpADSPError(dspPBPtr->ioResult, &displayStr); |
} |
break; |
case dspWrite: |
CopyPstr("\pdspWrite error. ",&displayStr); |
SetUpADSPError(dspPBPtr->ioResult, &displayStr); |
break; |
case dspAttention: |
/* ignore aborts that were caused by dspRemove or dspClose */ |
if ((dspPBPtr->ioResult != errAborted) |
&& (dspPBPtr->ioResult != errState)) |
{ |
CopyPstr("\pdspAttention error. ",&displayStr); |
SetUpADSPError(dspPBPtr->ioResult, &displayStr); |
} |
break; |
case dspOpen: |
/* ignore errAborted (-1279), request aborted by dspRemove or |
dspClose - the reason being that if we have a dspOpen (ocPassive |
mode) issued and then we want to connect to another machine, we |
must first close the connection end (cancelling the passive open) |
which would result in this error */ |
if (dspPBPtr->ioResult != errAborted) |
{ |
CopyPstr("\pdspOpen error. ",&displayStr); |
SetUpADSPError(dspPBPtr->ioResult, &displayStr); |
} |
break; |
case dspCLListen: |
CopyPstr("\pdspCLListen error. ",&displayStr); |
SetUpADSPError(dspPBPtr->ioResult, &displayStr); |
break; |
default: |
CopyPstr("\pError: ",&displayStr); |
NumToString(dspPBPtr->ioResult,theError); |
PStrCat(theError,(Ptr)displayStr); |
} |
/* if we have a message we want to show, put up a dialog |
for the user */ |
if (displayStr[0] != 0) |
{ |
ParamText(displayStr,"\p","\p","\p"); |
itemHit = Alert(rErrorDialog, nil); |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14