home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1999 / MacHack 1999.toast / The Hacks / IrComm Remote / DVDRemote / Hack / zzBackup / SerDemo.c
Encoding:
C/C++ Source or Header  |  1999-06-20  |  17.5 KB  |  737 lines  |  [TEXT/MPS ]

  1.  
  2. #include    <Types.h>
  3. //#include    <SysEqu.h>
  4. #include    <Resources.h>
  5. #include    <QuickDraw.h>
  6. #include    <Fonts.h>
  7. #include    <Events.h>
  8. #include    <Menus.h>
  9. #include    <Controls.h>
  10. #include    <Dialogs.h>
  11. #include    <Memory.h>
  12. #include    <Files.h>
  13. #include    <Devices.h>
  14. #include    <Serial.h>
  15. #include    <Timer.h>
  16. #include    <OSUtils.h>
  17. #include    <Processes.h>
  18. #include    <Gestalt.h>
  19. #include    <Errors.h>
  20. #include    <string.h>
  21. #include    <Speech.h>
  22.  
  23.  
  24. #define        rMonitor        1000
  25. #define        kSendButton        1
  26. #define        kStopButton        2
  27. #define        kQuitButton        3
  28. #define        kMsgBox            4
  29. #define        kSendSpinner    5
  30. #define        kRcvSpinner        7
  31. #define        kHoldFlag        9
  32. #define        kBreakButton    10
  33.  
  34. #define        rSerDataRsrc    128
  35. #define        rSpinnerIcon    1000
  36. #define        rHeldIcon        128
  37. #define        rNotHeldIcon    129
  38.  
  39. #define        rPortOpenALRT    256
  40. #define        kReset            2
  41.  
  42. #define        kCtlEnable        0
  43. #define        kCtlDisable        255
  44. #define        kSerBufSize        16384
  45. #define        kSerRdSize        64
  46. #define        kSerConfig        baud9600 + noParity + data8 + stop10
  47. #define        kBreakLength    666                // serial break length in milliseconds 
  48.  
  49. #define drvrName 0x12                // offset to driver name in 'DRVR' std. header 
  50.  
  51. #define dOpened  5
  52. #define dRAMBased  6
  53. #define drvrActive  7            // Device Manager DCtlFlag bits 
  54.                 
  55. #define kSerStatus  8
  56. #define kSerClrBrk  11            // Serial Driver csCodes 
  57. #define kSerSetBrk  12
  58. #define kSerHShakeDTR  14
  59. #define breakR0  128                // mask for break bit in SCC RR0 -- See TN #56 
  60. #define breakErr  8                    // mask for break bit in cumErrs -- System 7.0 
  61.  
  62. #define kDVDName "\pApple DVD Player"
  63. #define kCDName "\pAppleCD Audio Player"
  64.  
  65. /*
  66. typedef struct {
  67.     IOParam        fIOParam;
  68.     long        appA5;
  69. } ExtIOParam;
  70.  
  71. typedef struct {
  72.     TMTask        fTMTask;
  73.     long        appA5;
  74. } ExtTMTask;
  75.  
  76. typedef struct {
  77.     unsigned char    readR0;
  78.     unsigned char    deltaBits;
  79.     short            drvrPosting;
  80. } SERDEventMessage;
  81. */
  82.  
  83.  
  84. //Boolean        gHeldOff,
  85. //            gAllDone = false,
  86. //            gShouldSend = false,
  87. //            gReload = false,
  88. //            gKillBreak = false,
  89. //            gBreakReceived = false;
  90.  
  91. Ptr            gpSerBuf, *ghSerBuf,            // serial receive buffer
  92.             gpOutputData, *ghOutputData,    // send buffer
  93.             gpBitBucket, *ghBitBucket;        // receive processing buffer
  94.  
  95. long        gOutputDataSize;
  96. IOParam        *gpSendPB, **ghSendPB;        // for PBWrite calls to send data
  97. short        gSysVersion,
  98.             gOutRefNum, gInRefNum,
  99. //            gSendCount = 0,
  100.             gBitBucketCount = 0;
  101. //char        *panicString = "Help! I'm stuffed! And here's a bunch of characters to prove it!\n\r";
  102. TMTask        gPostEventTask;
  103.  
  104.  
  105.  
  106. short    Initialize (void);
  107. void    CleanUp (void);
  108. Boolean    OpenSERD (void);
  109. void    CloseSERD (void);
  110. void    DoIOStuff (void);
  111. OSErr    SendData (void);
  112. void    CheckSerData (long reqBytes);
  113. void    CheckSerStatus (void);
  114. pascal Boolean NullGrabber (DialogPtr, EventRecord *evt, short *itemHit);
  115. pascal void    SendCompRout (void);
  116. pascal void FlagBreakTimeout (void);
  117. void ProcessBitBucket(void);
  118. void PrimeTMTask(void);
  119. void ProcessString(unsigned char* s);
  120.  
  121. //#pragma parameter PostEventProc(__A0)
  122. pascal void PostEventProc (void);
  123.  
  124. //OSErr    AssertDrvrOpen (Str255 name, short *refNum);
  125.  
  126. //ParmBlkPtr GetParmBlkPtr (void) = 0x2008;        // MOVE.L A0,D0 
  127. //TMTaskPtr GetTMTaskPtr (void) = 0x2009;            // MOVE.L A1,D0 
  128.  
  129. //#pragma parameter __D0 PBControlImmed(__A0)
  130. //pascal OSErr PBControlImmed(ParmBlkPtr paramBlock) = 0xA204;        // _Control ,IMMED 
  131.  
  132. //#pragma parameter __D0 PBStatusImmed(__A0)
  133. //pascal OSErr PBStatusImmed(ParmBlkPtr paramBlock) = 0xA205;            // _Status ,IMMED 
  134.  
  135.  
  136.  
  137. void main (void)
  138. {
  139.     InitGraf(&qd.thePort);
  140.     InitFonts();
  141.     InitWindows();
  142.     InitMenus();
  143.     InitDialogs(NULL);
  144.     InitCursor();
  145.     
  146.     if (Initialize() == noErr) {
  147.         
  148.         if (OpenSERD()) {    // open the Serial Driver 
  149.             DoIOStuff();
  150.             CloseSERD();    // close the Serial Driver 
  151.         }
  152.         CleanUp();
  153.     }
  154.     
  155. }
  156.  
  157. //#define kInputDriver "\p.AIn"
  158. //#define kOutputDriver "\p.AOut"
  159. #define kInputDriver "\p.IrIn"
  160. #define kOutputDriver "\p.IrOut"
  161.  
  162.  
  163. Boolean OpenSERD (void)
  164. {
  165.     OSErr    openOutErr, openInErr;
  166.     OSErr    setBufErr, setCfgErr, setHskErr;
  167.     SerShk    hskFlags;
  168. //    long    finalTicks;
  169.     Boolean    takeOverPort = true;
  170. //    Boolean    openAOut, openAIn;
  171.     
  172. /*    openAOut = AssertDrvrOpen(kOutputDriver, &gOutRefNum) == noErr;
  173.     openAIn = AssertDrvrOpen(kInputDriver, &gInRefNum) == noErr;
  174.     if (openAOut || openAIn) {
  175.         if (takeOverPort = CautionAlert(rPortOpenALRT, nil) == kReset) {
  176.             if (openAIn) {
  177.                 KillIO(gInRefNum);
  178.                 CloseDriver(gInRefNum);
  179.             }
  180.             if (openAOut) {
  181.                 KillIO(gOutRefNum);
  182.                 CloseDriver(gOutRefNum);
  183.             }
  184.         }
  185.     }
  186.     
  187.     if (takeOverPort) {
  188. */
  189.         openOutErr = OpenDriver(kOutputDriver, &gOutRefNum);
  190.         openInErr = OpenDriver(kInputDriver, &gInRefNum);
  191.         
  192.         if (openOutErr == noErr && openInErr == noErr) {
  193.                     
  194.             // It's always good to first set a non-default input buffer, if desired. 
  195.             // There is no output buffering, so specify only the input driver.       
  196.             
  197.             setBufErr = SerSetBuf(gInRefNum, gpSerBuf, kSerBufSize);
  198.             
  199.             hskFlags.fXOn = false;
  200.             hskFlags.fCTS = true;
  201.             hskFlags.xOn = 0x11;
  202.             hskFlags.xOff = 0x13;
  203.             hskFlags.errs = 0;
  204.             
  205.             if (gSysVersion >= 0x0700) {
  206.                 hskFlags.evts = 0;                // I can use new means of break detection. 
  207.             }
  208.             else {
  209.                 hskFlags.evts = breakEvent;        // I need the driver to post break events. 
  210.             }
  211.             
  212.             hskFlags.fInX = false;
  213.             hskFlags.fDTR = true;
  214.             
  215.             // SerHShake() does not support full DTR/CTS hardware handshaking. You   
  216.             // accomplish the same thing and more with a Control call and csCode 14. 
  217.             // You only need to specify hskFlags once, to the output driver.         
  218.             
  219.             setHskErr = Control(gOutRefNum, kSerHShakeDTR, (Ptr) &hskFlags);
  220.  
  221.             // Now reset both input and output drivers with the same configuration.  
  222.             // Only a single call to the output driver is necessary to do this.      
  223.             // Differing concurrent input/output baud rates are not supported.       
  224.             
  225.             setCfgErr = SerReset(gOutRefNum, kSerConfig);
  226.             
  227.         }
  228.         else DebugStr("\pCan't open driver");
  229. //    }
  230.     
  231.     return takeOverPort;
  232. }
  233.  
  234.  
  235.  
  236. void CloseSERD (void)
  237. {
  238.     OSErr    killErr, closeOutErr, closeInErr;
  239.  
  240.     killErr = KillIO(gInRefNum);
  241.     closeInErr = CloseDriver(gInRefNum);
  242.  
  243.     killErr = KillIO(gOutRefNum);
  244.     closeOutErr = CloseDriver(gOutRefNum);
  245.  
  246. }
  247.  
  248.         
  249.  
  250.  
  251. void CheckSerData (long /*reqBytes*/)
  252. {
  253.     OSErr    checkBufErr, serRdErr;
  254.     long    charCount;
  255.     
  256.     // long    finalTicks;
  257.     // register long overrun;
  258.     
  259.     checkBufErr = SerGetBuf(gInRefNum, &charCount);
  260.     if (checkBufErr == noErr) {
  261.     
  262.         // The general strategy here is this: if number of available characters 
  263.         // meets a certain minimum threshold, then I read in everything in the  
  264.         // buffer. If I get delayed, I'll catch up quickly.                     
  265.  
  266. //        if (charCount != 0 && charCount >= reqBytes) {
  267.         if (charCount > 0) {
  268.             
  269.             serRdErr = FSRead(gInRefNum, &charCount, &gpBitBucket[gBitBucketCount]);
  270.             if (serRdErr == noErr) {
  271.                 gBitBucketCount += charCount;
  272.                 gpBitBucket[gBitBucketCount] = 0xFF; // append an 'unfinished string' terminator
  273. //                DebugStr("\pgotsome!");
  274.             }
  275.         }
  276.     }
  277. }
  278.  
  279.  
  280.  
  281. void DoIOStuff (void)
  282. {
  283. //    DialogPtr        serMonitor;
  284. //    OSErr            primeErr;
  285. //    short            itemHit, itemType;
  286. //    ControlHandle    sendItem, stopItem, breakItem;
  287. //    Handle            spinner, flag, item;
  288. //    Rect            box;
  289. //    CntrlParam        breakPB;
  290.     
  291. //    serMonitor = GetNewDialog(rMonitor, NULL, NULL);
  292. //    SetPort((GrafPtr) serMonitor);
  293.     
  294.     // send some data
  295.     SendData();
  296.     
  297. //    PrimeTMTask();
  298.     
  299.     while(!Button())
  300.     {
  301.         EventRecord theEvent;
  302.         CheckSerData(4);
  303.         WaitNextEvent(everyEvent, &theEvent, 10, 0);
  304.         
  305.         ProcessBitBucket();
  306.         
  307. /*        if(gRcvCount >= 4)
  308.         {
  309.             gpBitBucket[5] = 0;
  310.             c2pstr(gpBitBucket);
  311.             DebugStr((unsigned char*)gpBitBucket);
  312.         }
  313. */
  314.     }
  315.         
  316. }
  317.  
  318.  
  319. void ProcessBitBucket(void)
  320. {
  321.     char* s = gpBitBucket;
  322.     short i = 0;
  323.     Boolean foundString = false;
  324.     
  325.     while(foundString == false && i < gBitBucketCount)
  326.     {
  327.         if(s[i] == '\r')
  328.         {
  329.             foundString = true;
  330.             s[i] = 0; // null terminate the string
  331.         }
  332.         if(s[i] == 0xFF)
  333.         {
  334.             foundString = false;
  335.             break;
  336.         }
  337.         
  338.         i++;
  339.     }
  340.     
  341.     if(foundString == true) 
  342.     {
  343.         c2pstr(s);
  344.         SpeakString((unsigned char*)s);
  345.         
  346.         ProcessString((unsigned char*)s);
  347.         
  348.         gBitBucketCount -= i;
  349.         BlockMove(&s[i], &s[0], gBitBucketCount);
  350.     }
  351.     
  352.     return;
  353. }
  354.  
  355. void ProcessString(unsigned char* s)
  356. {
  357.     if(EqualString(s, "\pPlay", false, false))
  358.     {
  359.         PostEvent(keyDown, ' ');
  360.     }
  361.     else if(EqualString(s, "\pPause", false, false))
  362.     {
  363.         PostEvent(keyDown, ' ');
  364.     }
  365.     else if(EqualString(s, "\pStop", false, false))
  366.     {
  367.         
  368.     }
  369.     else if(EqualString(s, "\pFast Forward", false, false))
  370.     {
  371.         
  372.     }
  373.     else if(EqualString(s, "\pRewind", false, false))
  374.     {
  375.         
  376.     }
  377.     
  378.     return;
  379. }
  380.  
  381. OSErr SendData (void)
  382. //short SendData (void)
  383. {
  384.     gpSendPB->ioCompletion = 0;//(ProcPtr)0;// SendCompRout;
  385.     gpSendPB->ioRefNum = gOutRefNum;
  386.     gpSendPB->ioBuffer = gpOutputData;
  387.     gpSendPB->ioReqCount = gOutputDataSize;
  388. //    ((ExtIOParam *) gpSendPB)->appA5 = SetCurrentA5();    // completion routine needs A5 
  389. //    gReload = true;
  390.     
  391. //    return PBWriteAsync((ParmBlkPtr) gpSendPB);            // asynchronous self-sustaining sends 
  392.     return PBWriteSync((ParmBlkPtr) gpSendPB);            // asynchronous self-sustaining sends 
  393.  
  394. }
  395.  
  396.  
  397.  
  398. short Initialize (void)
  399. {
  400.     long    result;
  401.     OSErr    gestErr;
  402.     
  403.     gestErr = Gestalt(gestaltSystemVersion, &result);
  404.     gSysVersion = result;
  405.     
  406.     ghSendPB = (IOParam **) NewHandle( sizeof(IOParam));
  407.     if (ghSendPB != NULL) {
  408.         MoveHHi((Handle) ghSendPB);
  409.         HLock((Handle) ghSendPB);
  410.         gpSendPB = *ghSendPB;
  411.     }
  412.     else {
  413.         return MemError();
  414.     }
  415.  
  416.     ghSerBuf = NewHandle(kSerBufSize);
  417.     if (ghSerBuf != NULL) {
  418.         MoveHHi((Handle) ghSerBuf);
  419.         HLock((Handle) ghSerBuf);
  420.         gpSerBuf = *ghSerBuf;
  421.     }
  422.     else {
  423.         DisposeHandle((Handle) ghSendPB);
  424.         return MemError();
  425.     }
  426.     
  427.     ghBitBucket = NewHandle(kSerBufSize);
  428.     if (ghBitBucket != NULL) {
  429.         MoveHHi(ghBitBucket);
  430.         HLock(ghBitBucket);
  431.         gpBitBucket = *ghBitBucket;
  432.     }
  433.     else {
  434.         DisposeHandle((Handle) ghSendPB);
  435.         DisposeHandle((Handle) ghSerBuf);
  436.         return MemError();
  437.     }
  438.     
  439.     ghOutputData = Get1Resource('sDAT', rSerDataRsrc);
  440.     if (ghOutputData != NULL) {
  441.         MoveHHi(ghOutputData);
  442.         HLock(ghOutputData);
  443.         gpOutputData = *ghOutputData;
  444.         gOutputDataSize = GetResourceSizeOnDisk(ghOutputData);
  445.     }
  446.     else {
  447.         DisposeHandle((Handle) ghSendPB);
  448.         DisposeHandle((Handle) ghSerBuf);
  449.         DisposeHandle(ghBitBucket);
  450.         return ResError();
  451.     }
  452.     
  453. /*    // I use a Time Manager task to time breaks. This is where I install it.
  454.     
  455.     gUnBreakTask.fTMTask.tmAddr = FlagBreakTimeout;
  456.     gUnBreakTask.appA5 = SetCurrentA5();
  457.     InsTime((QElemPtr) &gUnBreakTask);
  458. */
  459.     
  460.     return noErr;
  461. }
  462.  
  463.  
  464.  
  465. void CleanUp (void)
  466. {
  467.  
  468.     DisposeHandle((Handle) ghSendPB);
  469.     DisposeHandle(ghSerBuf);
  470.     DisposeHandle(ghBitBucket);
  471. }
  472.  
  473.  
  474.  
  475. #pragma mark • Commented out
  476.  
  477.  
  478. /*
  479.     while (!gAllDone) {
  480.         
  481.             CheckSerStatus();
  482.         
  483.     
  484.             if (gShouldSend && gReload) {
  485.                 gSendCount++;                // increment a counter for the output spinner 
  486.                 gReload = !gReload;
  487.             }
  488.             
  489.         // The break timer simply sets a global flag which I use to indicate when  
  490.         // to clear a break condition. Again, I use an immediate Control call, but 
  491.         // primarily for consistency, and also to show off.                        
  492.             
  493.             if (gKillBreak) {
  494.                 breakPB.ioCRefNum = gOutRefNum;
  495.                 breakPB.csCode = kSerClrBrk;
  496.                 PBControlImmed((ParmBlkPtr) &breakPB);        // SerClrBrk(), but IMMED 
  497.                 gKillBreak = !gKillBreak;
  498.                 GetDialogItem(serMonitor, kBreakButton, &itemType, &(Handle) breakItem, &box);
  499.                 HiliteControl(breakItem, kCtlEnable);
  500.             }
  501.         
  502.         // If another area of the program detects a break, I flag the occurrence here. 
  503.         
  504.             if (gBreakReceived) {
  505.                 SysBeep(1);
  506.                 SysBeep(1);
  507.                 gBreakReceived = !gBreakReceived;
  508.             }
  509.  
  510.         
  511.         // In lieu of an event loop, I just use a modal dialog with a relatively  
  512.         // simple (but unusual) filterProc. This is not a good example of how to  
  513.         // write an app. Modal dialogs are evil and to be avoided if possible.    
  514.         // Nonetheless, the filterProc is an interesting example unto itself....  
  515.     
  516.             ModalDialog(NullGrabber, &itemHit);
  517.             switch (itemHit) {
  518.                 
  519.                 case kStopButton:
  520.                     if (gShouldSend) {
  521.                         gShouldSend = !gShouldSend;
  522.                     }
  523.                     break;
  524.                 
  525.                 case kSendButton:
  526.                     if (!gShouldSend) {
  527.                         gShouldSend = !gShouldSend;
  528.                         primeErr = SendData();
  529.                     }
  530.                     break;
  531.                 
  532.                 case kBreakButton:
  533.                 
  534.                 // In another possible Mac IIfx IOP bug, SerSetBrk() called synchronously  
  535.                 // appears to hang the machine if an async write is pending. Since that is 
  536.                 // often the case (at least in this application) I work around the problem 
  537.                 // by making the Control call immediate--this prevents the hang, but also  
  538.                 // raises another interesting issue about when break is actually asserted. 
  539.                 
  540.                     breakPB.ioCRefNum = gOutRefNum;
  541.                     breakPB.csCode = kSerSetBrk;
  542.                     PBControlImmed((ParmBlkPtr) &breakPB);        // SerSetBrk(), but IMMED 
  543.                     
  544.                 // With break asserted, I prime a Time Manager task to flag the end of    
  545.                 // the break, and disable the Break button so that it cannot be selected  
  546.                 // again until break is negated.                                          
  547.                 
  548.                     PrimeTime((QElemPtr) &gUnBreakTask, kBreakLength);
  549.                     GetDialogItem(serMonitor, kBreakButton, &itemType, &(Handle) breakItem, &box);
  550.                     HiliteControl(breakItem, kCtlDisable);
  551.                     break;
  552.                 
  553.                 case kQuitButton:
  554.                     gAllDone = true;
  555.                     break;
  556.                 
  557.             }
  558.     }
  559.     */
  560.     
  561. //    DisposeDialog(serMonitor);
  562.  
  563.  
  564. /*
  565. pascal void FlagBreakTimeout (void)
  566. {
  567.     long    oldA5;
  568.     
  569.     oldA5 = SetA5(((ExtTMTask *) GetTMTaskPtr())->appA5);        // retrieve A5 
  570.     
  571.     gKillBreak = true;
  572.     
  573.     SetA5(oldA5);
  574.     
  575. }
  576. */
  577.  
  578.  
  579. /*
  580. pascal Boolean NullGrabber (DialogPtr dPtr, EventRecord *evt, short *itemHit)
  581. {
  582.     EventRecord    driverEvent;
  583.     
  584.     // Without this filterProc, none of the animation works: 
  585.     
  586.     // In order to keep things rolling along even when there are no events    
  587.     // such as mouse clicks or keystrokes, I have to return true in response  
  588.     // to null events. This is unusual, but otherwise ModalDialog() "handles" 
  589.     // null events by eating them and waiting for something better. This is   
  590.     // bad if I need to turn the spinner or clear a break condition.          
  591.     
  592.     // Also, I check for driver events here in order to detect breaks. 
  593.     
  594.     if (GetNextEvent(driverMask, &driverEvent)) {
  595.         if ((*(SERDEventMessage *) &driverEvent.message).drvrPosting == gInRefNum) {
  596.             gBreakReceived = ((*(SERDEventMessage *) &driverEvent.message).readR0 & breakR0) != 0;
  597.         }
  598.     }
  599.     
  600.     if (evt->what == nullEvent) {
  601.         *itemHit = 0;
  602.         return true;
  603.     }
  604.     
  605.     else {
  606.         return false;
  607.     }
  608.     
  609. }*/
  610.  
  611. /*
  612.  
  613. pascal void SendCompRout (void)
  614. {
  615.     long    oldA5;
  616.     
  617.     oldA5 = SetA5(((ExtIOParam *) GetParmBlkPtr())->appA5);        // retrieve A5 
  618.     
  619.     if (gShouldSend && !gAllDone) {
  620.         gReload = true;
  621.         gpSendPB->ioCompletion = (ProcPtr) SendCompRout;
  622.         PBWriteAsync((ParmBlkPtr) gpSendPB);            // this is the self-sustaining part     
  623.     }
  624.     
  625.     SetA5(oldA5);
  626.     
  627. }
  628. */
  629.  
  630. /*
  631. OSErr AssertDrvrOpen (Str255 name, short *refNum)
  632. {
  633.     DCtlHandle    *pUTEntry;
  634.     Ptr            pDrvr;
  635.     OSErr        result = notOpenErr;        // assume not open 
  636.     short        unitNo;
  637.     char        *aDrvrName;
  638.     
  639.     // The point here is to determine whether a driver is open, given its name.  
  640.     // This allows one to check a driver to see if it's open without hard coding 
  641.     // its reference number. (Normally, the way to get the refNum is to open     
  642.     // the driver--but that defeats the whole purpose!)                          
  643.     // This is an extension of the code discussed in Tech Note #71.              
  644.     
  645.     *refNum = 0;
  646.     pUTEntry = *(DCtlHandle **) UTableBase;
  647.     for (unitNo = 0; unitNo < *(short *) UnitNtryCnt; unitNo++, pUTEntry++) {
  648.         if (*pUTEntry != nil && **pUTEntry != nil) {
  649.             if (((***pUTEntry).dCtlFlags & 1 << dRAMBased) != 0)
  650.                 pDrvr = *(Handle) (***pUTEntry).dCtlDriver;
  651.             else
  652.                 pDrvr = (***pUTEntry).dCtlDriver;
  653.             
  654.             if (pDrvr != nil) {
  655.                 aDrvrName = pDrvr + drvrName;
  656.                 if (memcmp(aDrvrName, name, 1 + name[0]) == 0) {
  657.                     // We found the one we're after. 
  658.                     *refNum = ~unitNo;
  659.                     if (((***pUTEntry).dCtlFlags & 1 << dOpened) != 0)
  660.                         result = noErr;
  661.                     break;
  662.                 }
  663.             }
  664.         }
  665.     }    
  666.     
  667.     return result;
  668. }
  669.  
  670. */
  671.  
  672.  
  673. /*
  674. void CheckSerStatus (void)
  675. {
  676.     OSErr        checkStatErr, panicErr;
  677.     IOParam        altSendPB, *pAltSendPB = &altSendPB;
  678.     CntrlParam    statPB;
  679.     SerStaRec    serStat;
  680.     
  681.     statPB.ioCRefNum = gInRefNum;
  682.     statPB.csCode = kSerStatus;
  683.     checkStatErr = PBStatusImmed((ParmBlkPtr) &statPB);
  684.     serStat =  *(SerStaRec *) &statPB.csParam;
  685.     
  686.     // I check to see if the remote system has told me to stop sending. 
  687.     
  688.     gHeldOff = (Boolean) serStat.ctsHold;
  689.     
  690.     // Check for errors. 
  691.     
  692.     if (serStat.cumErrs & swOverrunErr)
  693.         DebugStr("\pSoftware Overrun Error");
  694.     else if (serStat.cumErrs & parityErr)
  695.         DebugStr("\pParity Error");
  696.     else if (serStat.cumErrs & hwOverrunErr)
  697.         DebugStr("\pHardware Overrun Error");
  698.     else if (serStat.cumErrs & framingErr)
  699.         DebugStr("\pFraming Error");
  700.     
  701.     // If I have System 7.0 or better, I can check directly to see if   
  702.     // I've received a break. Usually I don't check for a feature this  
  703.     // way, but in this case I have no alternative.                     
  704.     
  705.     if (gSysVersion >= 0x0700) {
  706.         gBreakReceived = (serStat.cumErrs & breakErr) != 0;
  707.     }
  708.     
  709.     // All I do here is send a small "panic" packet of characters back  
  710.     // to the remote system when it fills _my_ buffer. I don't actually 
  711.     // know the exact state of my buffer, but I can see if I've told    
  712.     // the remote system to shut up, indicating that I'm mostly full.   
  713.     
  714.     if (checkStatErr == noErr) {
  715.         if (( (unsigned char) serStat.xOffSent & dtrNegated) != 0) {
  716.             pAltSendPB->ioCompletion = NULL;
  717.             pAltSendPB->ioRefNum = gOutRefNum;
  718.             pAltSendPB->ioBuffer = panicString;
  719.             pAltSendPB->ioReqCount = strlen(panicString);
  720.             PBWriteAsync((ParmBlkPtr) pAltSendPB);
  721.             
  722.             // The program may hang here if the user quits the    
  723.             // remote application first--that could hold off our  
  724.             // serial output, leaving a pending asynchronous I/O  
  725.             // request and keeping us in an infinite loop.        
  726.             
  727.             while (pAltSendPB->ioResult > 0) {}                // I'll fix it later. 
  728.             // The reason I do this instead of just calling it synchronously 
  729.             // is so that if I do hang, I'll hang in my code for an obvious  
  730.             // reason instead of hanging up in the Device Manager.           
  731.             panicErr = pAltSendPB->ioResult;
  732.         }
  733.     }
  734.     
  735.     
  736. }
  737. */