home *** CD-ROM | disk | FTP | other *** search
/ Black Art of 3D Game Programming / Black_Art_of_3D_Game_Programming.iso / source / borland / chap_9 / black9.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-20  |  14.2 KB  |  662 lines

  1.  
  2. // I N C L U D E S ///////////////////////////////////////////////////////////
  3.  
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <fcntl.h>
  11. #include <memory.h>
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <string.h>
  15.  
  16.  
  17. #include "black3.h"
  18. #include "black5.h"
  19. #include "black9.h"
  20.  
  21. // G L O B A L S /////////////////////////////////////////////////////////////
  22.  
  23. void (_interrupt _far *Old_Serial_ISR)();  // holds old com port interrupt handler
  24.  
  25. char serial_buffer[SERIAL_BUFF_SIZE];  // the receive buffer
  26.  
  27. int serial_end   = -1;                 // indexes into receive buffer
  28. int serial_start = -1;
  29. int serial_ch;
  30. int char_ready=0;                   // current character and ready flag
  31. int old_int_mask;                   // the old interrupt mask on the PIC
  32. int open_port;                      // the currently open port
  33. int serial_lock = 0;                // serial ISR semaphore so the buffer
  34.                                     // isn't altered will it is being written
  35.                                     // to by the ISR
  36. // G L O B A L S ////////////////////////////////////////////////////////////
  37.  
  38. char *modem_strings[]={"OK",             // these are the standard Hayes
  39.                        "CONNECT",        // response strings
  40.                        "RING",
  41.                        "NO CARRIER",
  42.                        "ERROR",
  43.                        "CONNECT 1200",
  44.                        "NO DIALTONE",
  45.                        "BUSY",
  46.                        "NO ANSWER",
  47.                        "CONNECT 0600",
  48.                        "CONNECT 2400",
  49.  
  50.                        "CARRIER 2400",   // experimental response strings
  51.                        "CONNECT 9600",
  52.                        "CONNECT 4800"};
  53.  
  54. //////////////////////////////////////////////////////////////////////////////
  55.  
  56. void _interrupt _far Serial_ISR(void)
  57. {
  58. // this is the serial ISR that is installed. It is called whenever a character
  59. // is received. The received character is then placed into the next position
  60. // in the input ring buffer
  61.  
  62. _asm sti
  63.  
  64. serial_ch = inp(open_port + SERIAL_RBF);
  65.  
  66. // wrap buffer index around
  67.  
  68. if (++serial_end > SERIAL_BUFF_SIZE-1)
  69.     serial_end = 0;
  70.  
  71. // move character into buffer
  72.  
  73. serial_buffer[serial_end] = serial_ch;
  74.  
  75. ++char_ready;
  76.  
  77. // restore PIC
  78.  
  79. outp(PIC_ICR,0x20);
  80.  
  81. } // end Serial_ISR
  82.  
  83. //////////////////////////////////////////////////////////////////////////////
  84.  
  85. int Serial_Ready(void)
  86. {
  87.  
  88. // this functions returns true if there are any characters waiting and 0 if
  89. // the buffer is empty
  90.  
  91. return(char_ready);
  92.  
  93. } // end Serial_Ready
  94.  
  95. //////////////////////////////////////////////////////////////////////////////
  96.  
  97. int Serial_Read(void)
  98. {
  99.  
  100. // this function reads a character from the circulating buffer and returns it
  101. // to the caller
  102.  
  103. int ch;
  104.  
  105. // test if there is a character(s) ready in buffer
  106.  
  107. if (serial_end != serial_start)
  108.    {
  109.  
  110.    // wrap buffer index if needed
  111.  
  112.    if (++serial_start > SERIAL_BUFF_SIZE-1)
  113.        serial_start = 0;
  114.  
  115.    // get the character out of buffer
  116.  
  117.    ch = serial_buffer[serial_start];
  118.  
  119.    // one less character in buffer now
  120.  
  121.    if (char_ready > 0)
  122.        --char_ready;
  123.  
  124.    // send data back to caller
  125.  
  126.    return(ch);
  127.  
  128.    } // end if a character is in buffer
  129. else
  130.    // buffer was empty return a NULL i.e. 0
  131.    return(0);
  132.  
  133. } // end Serial_Read
  134.  
  135.  
  136. //////////////////////////////////////////////////////////////////////////////
  137.  
  138. void Serial_Write(char ch)
  139. {
  140.  
  141. // this function writes a character to the transmit buffer, but first it
  142. // waits for the transmit buffer to be empty.  note: it is not interrupt
  143. // driven and it turns of interrupts while it's working
  144.  
  145. // wait for transmit buffer to be empty
  146.  
  147. while(!(inp(open_port + SERIAL_LSR) & 0x20)){}
  148.  
  149. // turn off interrupts for a bit
  150.  
  151. _asm cli
  152.  
  153. // send the character
  154.  
  155. outp(open_port + SERIAL_THR, ch);
  156.  
  157. // turn interrupts back on
  158.  
  159. _asm sti
  160.  
  161. } // end Serial_Write
  162.  
  163. //////////////////////////////////////////////////////////////////////////////
  164.  
  165. void Serial_Print(char *string,int cr)
  166. {
  167. // this function is used to print a string to the serial port
  168.  
  169. int index,      // looping variable
  170.     length;     // used for length of string
  171.  
  172. length = strlen(string);
  173.  
  174. // write each character
  175.  
  176. for (index=0; index<length; index++)
  177.     Serial_Write(string[index]);
  178.  
  179. // send a carriage return if requested
  180.  
  181. if (cr)
  182.     Serial_Write(13);
  183.  
  184. } // end Serial_Print
  185.  
  186. //////////////////////////////////////////////////////////////////////////////
  187.  
  188. int Serial_Open(int port_base, int baud, int configuration)
  189. {
  190.  
  191. // this function will open up the serial port, set it's configuration, turn
  192. // on all the little flags and bits to make interrupts happen and load the
  193. // ISR
  194.  
  195. unsigned char data;
  196.  
  197. // save the port I/O address for other functions
  198.  
  199. open_port = port_base;
  200.  
  201. // first set the baud rate
  202.  
  203. // turn on divisor latch registers
  204.  
  205. outp(port_base + SERIAL_LCR, SERIAL_DIV_LATCH_ON);
  206.  
  207. // send low and high bytes to divsor latches
  208.  
  209. outp(port_base + SERIAL_DLL, baud);
  210. outp(port_base + SERIAL_DLH, 0);
  211.  
  212. // set the configuration for the port
  213.  
  214. outp(port_base + SERIAL_LCR, configuration);
  215.  
  216. // enable the interrupts
  217.  
  218. data = inp(port_base + SERIAL_MCR);
  219. data = SET_BITS(data,SERIAL_GP02);
  220. outp(port_base + SERIAL_MCR, data);
  221.  
  222. outp(port_base + SERIAL_IER, 1);
  223.  
  224. // hold off on enabling PIC until we have the ISR installed
  225.  
  226. if (port_base == COM_1)
  227.    {
  228.    Old_Serial_ISR = _dos_getvect(INT_SERIAL_PORT_0);
  229.    _dos_setvect(INT_SERIAL_PORT_0, Serial_ISR);
  230.  
  231.    }
  232. else
  233.    {
  234.    Old_Serial_ISR = _dos_getvect(INT_SERIAL_PORT_1);
  235.    _dos_setvect(INT_SERIAL_PORT_1, Serial_ISR);
  236.    }
  237.  
  238. // enable the recieve character interrupt on PIC for selected comm port
  239.  
  240. old_int_mask = inp(PIC_IMR);
  241.  
  242. outp(PIC_IMR, (port_base==COM_1) ? (old_int_mask & 0xEF) : (old_int_mask & 0xF7 ));
  243.  
  244. return(1);
  245.  
  246. } // Serial_Open
  247.  
  248. //////////////////////////////////////////////////////////////////////////////
  249.  
  250. int Serial_Close(void)
  251. {
  252.  
  253. // this function closes the port which entails turning off interrupts and
  254. // restoring the old interrupt vector
  255.  
  256. unsigned char data;
  257.  
  258. // disable the comm port interrupts
  259.  
  260. data = inp(open_port + SERIAL_MCR);
  261. data = RESET_BITS(data,SERIAL_GP02);
  262.  
  263. outp(open_port + SERIAL_MCR, data);
  264.  
  265. outp(open_port + SERIAL_IER, 0);
  266. outp(PIC_IMR, old_int_mask );
  267.  
  268. // replace old comm port isr
  269.  
  270. if (open_port == COM_1)
  271.    {
  272.    _dos_setvect(INT_SERIAL_PORT_0, Old_Serial_ISR);
  273.    }
  274. else
  275.    {
  276.    _dos_setvect(INT_SERIAL_PORT_1, Old_Serial_ISR);
  277.    }
  278.  
  279. return(1);
  280.  
  281. } // end Serial_Close
  282.  
  283. //////////////////////////////////////////////////////////////////////////////
  284.  
  285. void Serial_Flush(void)
  286. {
  287. // this function flushes out the serial buffer
  288.  
  289. int index; // looping index
  290.  
  291. // read up to 32 characters
  292.  
  293. for (index=0; index<32; index++)
  294.     {
  295.     Serial_Read();
  296.     Time_Delay(1);
  297.     } // end for index
  298.  
  299. } // end Serial_Flush
  300.  
  301. //////////////////////////////////////////////////////////////////////////////
  302.  
  303. void Modem_Control(int command)
  304. {
  305. // this function is used to control specific aspects of the modem hardware
  306.  
  307. unsigned char data;
  308.  
  309. // which command is being issued?
  310.  
  311. switch(command)
  312.       {
  313.       case MODEM_DTR_ON:
  314.            {
  315.            // read modem control register
  316.  
  317.            data = inp(open_port + SERIAL_MCR);
  318.            data = SET_BITS(data,1);
  319.            outp(open_port + SERIAL_MCR,data);
  320.  
  321.            } break;
  322.  
  323.       case MODEM_DTR_OFF:
  324.            {
  325.            // read modem control register
  326.  
  327.               data = inp(open_port + SERIAL_MCR);
  328.            data = RESET_BITS(data,1);
  329.               outp(open_port + SERIAL_MCR,data);
  330.  
  331.            } break;
  332.  
  333.       default: break;
  334.  
  335.       } // end switch
  336.  
  337. // wait a sec for it to take effect
  338.  
  339. Time_Delay(DELAY_1_SECOND);
  340.  
  341. } // end Modem_Control
  342.  
  343. ////////////////////////////////////////////////////////////////////////////////
  344.  
  345. int Initialize_Modem(char *extra_init)
  346. {
  347. // this function will initialize the modem and prepare it for use
  348. // if your modem has some specific sequence that must be sent to reset
  349. // it then send it in the extra string, otherwise set extra equal to NULL
  350.  
  351. int result;
  352.  
  353. // send reset command
  354.  
  355. Modem_Send_Command("ATZ");
  356.  
  357. result = Modem_Result(NULL,0);
  358.  
  359. if (result!=MODEM_OK)
  360.     return(result);
  361.  
  362. // allow dtr line to be controlled
  363.  
  364. //Modem_Send_Command("AT&D2");
  365.  
  366. //result = Modem_Result(NULL,0);
  367.  
  368. //if (result!=MODEM_OK)
  369. //    return(result);
  370.  
  371. // place modem in direct asynchronous mode
  372.  
  373. Modem_Send_Command("AT&Q0");
  374.  
  375. result = Modem_Result(NULL,0);
  376.  
  377. if (result!=MODEM_OK)
  378.     return(result);
  379.  
  380. // send hardware specific modem command
  381.  
  382. if (extra_init && strlen(extra_init)>=2)
  383.    {
  384.  
  385.    Modem_Send_Command(extra_init);
  386.  
  387.    result=Modem_Result(NULL,0);
  388.  
  389.    } // end if
  390.  
  391. return(result);
  392.  
  393. } // end Initialize_Modem
  394.  
  395. ///////////////////////////////////////////////////////////////////////////////
  396.  
  397. void Modem_Send_Command(char *buffer)
  398. {
  399. // this function sends a command string to the modem
  400.  
  401. int index,    // looping variable
  402.     length;   // length of command
  403.  
  404. // write the string out
  405.  
  406. length = strlen(buffer);
  407.  
  408. for (index=0; index<length; index++)
  409.     Serial_Write(buffer[index]);
  410.  
  411. // printf("\nSending:%s",buffer);
  412.  
  413. // send a carriage return
  414.  
  415. Serial_Write(13);
  416.  
  417. Time_Delay(DELAY_1_SECOND);
  418.  
  419. } // end Modem_Send_Command
  420.  
  421. //////////////////////////////////////////////////////////////////////////////
  422.  
  423. int Serial_Read_Wait(void)
  424. {
  425. // this function waits for a character to be ready and then returns it
  426.  
  427. while(!Serial_Ready());
  428.  
  429. // return the character
  430.  
  431. return(Serial_Read());
  432.  
  433. } // end Serial_Read_Wait
  434.  
  435. ///////////////////////////////////////////////////////////////////////////////
  436.  
  437. int Modem_Result(char *output,int exit_enable)
  438. {
  439. // this function is a bit messy (as are all parsing functions), it is used
  440. // to rtrieve a response from the mode, however, it will disregard any
  441. // echoed commands, also, the last parameter exit_enable is used as a flag
  442. // to allow the keyboard to force an exit, this is useful in a situation
  443. // such as waiting for an answer or waiting to be called, in any case, this
  444. // give the function an exit avenue, the exit is enabled by pressing a key
  445. // on the keyboard, however, the keyboard handler must be installed for
  446. // this to work!
  447.  
  448. int index=0,        // looping variable
  449.     start=0;
  450.  
  451. char ch,          // woring character
  452.      buffer[64];  // working buffer
  453.  
  454. // hunt for start of response
  455.  
  456. while(1)
  457.      {
  458.      // is a character ready?
  459.  
  460.      if (Serial_Ready())
  461.         {
  462.         if (Serial_Read()==10)
  463.            break;
  464.  
  465.         } // end if a character is ready
  466.  
  467.      // test if user is trying to abort
  468.  
  469.      if (exit_enable && (kbhit() || keys_active))
  470.         return(MODEM_USER_ABORT);
  471.  
  472.      } // end while
  473.  
  474. // read the response
  475.  
  476. while(1)
  477.      {
  478.      // is a character ready?
  479.  
  480.      if (Serial_Ready())
  481.         {
  482.         ch = Serial_Read();
  483.  
  484.         if (ch==10)
  485.            break;
  486.  
  487.         buffer[index++] = ch;
  488.  
  489.         } // end if a character is ready
  490.  
  491.      // test if user is trying to abort
  492.  
  493.      if (exit_enable && (kbhit() || keys_active))
  494.         return(MODEM_USER_ABORT);
  495.  
  496.      } // end while
  497.  
  498. // terminate response
  499.  
  500. buffer[index-1] = 0;
  501.  
  502. // printf("\nReceived:%s",buffer);
  503.  
  504. // copy the result into the output string
  505.  
  506. if (output!=NULL)
  507.    strcpy(output,buffer);
  508.  
  509. // compute which response has been given
  510.  
  511. for (index=0; index<NUM_MODEM_RESPONSES; index++)
  512.     {
  513.     // test the response to next response string
  514.  
  515.     if (strcmp(modem_strings[index],buffer)==0)
  516.        return(index);
  517.  
  518.     } // end for index
  519.  
  520. // there must be some kind of error
  521.  
  522. return(MODEM_ERROR);
  523.  
  524. } // end Modem_Result
  525.  
  526. ///////////////////////////////////////////////////////////////////////////////
  527.  
  528. int Make_Connection(char *number)
  529. {
  530. // this function calls up the sent phone number and returns true if the
  531. // connection was made or false if it wasn't
  532.  
  533. int result;
  534. char command[64];
  535.  
  536. // flush serial buffers
  537.  
  538. Serial_Flush();
  539.  
  540. // enable the DTR line
  541.  
  542. Modem_Control(MODEM_DTR_ON);
  543.  
  544. Time_Delay(DELAY_1_SECOND);
  545.  
  546. // dial number
  547.  
  548. sprintf(command,"ATDT%s",number);
  549.  
  550. // make the call
  551.  
  552. Modem_Send_Command(command);
  553.  
  554. result = Modem_Result(NULL,1);
  555.  
  556. // test the result
  557.  
  558. if (result==MODEM_CONNECT      ||
  559.     result==MODEM_CONNECT_1200 ||
  560.     result==MODEM_CONNECT_2400)
  561.     {
  562.     // a successful connection has been made
  563.  
  564.     return(result);
  565.  
  566.     } // end if connection made
  567. else
  568.    {
  569.    // there must be a problem, hang up the phone
  570.  
  571.    Hang_Up();
  572.  
  573.    // return the error
  574.  
  575.    return(result);
  576.  
  577.    } // end else
  578.  
  579. } // end Make_Connection
  580.  
  581. ////////////////////////////////////////////////////////////////////////////////
  582.  
  583. int Wait_For_Connection(void)
  584. {
  585. // this function will wait for a connection to be made and return true
  586. // when this occurs. the function will return false if a connection isn't
  587. // made or in a specific amount of time or if a key is pressed
  588.  
  589. int result;
  590.  
  591. char command[64];
  592.  
  593. // flush serial buffers
  594.  
  595. Serial_Flush();
  596.  
  597. // make sure modem is hung up
  598.  
  599. Hang_Up();
  600.  
  601. Modem_Control(MODEM_DTR_ON);
  602.  
  603. // wait for phone to ring...
  604.  
  605. result =  Modem_Result(NULL,1);
  606.  
  607. // was that a ring?
  608.  
  609. if (result == MODEM_RING)
  610.    {
  611.  
  612.    // tell modem to answer
  613.  
  614.    Modem_Send_Command("ATA");
  615.  
  616.    result = Modem_Result(NULL,1);
  617.  
  618.    // test the result
  619.  
  620.    if (result==MODEM_CONNECT ||
  621.        result==MODEM_CONNECT_1200 ||
  622.        result==MODEM_CONNECT_2400)
  623.        {
  624.        // a successful connection has been made
  625.  
  626.        return(result);
  627.  
  628.        } // end if connection made
  629.    else
  630.       {
  631.       // there must be a problem, hang up the phone
  632.  
  633.       Hang_Up();
  634.  
  635.       // return the error
  636.  
  637.       return(result);
  638.  
  639.       } // end else
  640.  
  641.    } // end if ringing
  642.  
  643. } // end Wait_For_Connection
  644.  
  645. ///////////////////////////////////////////////////////////////////////////////
  646.  
  647. int Hang_Up(void)
  648. {
  649. // this function hangs up the phone and places the modem back into it's command
  650. // state
  651.  
  652. int result;
  653.  
  654. // drop dtr line
  655.  
  656. Modem_Control(MODEM_DTR_OFF);
  657.  
  658. return(MODEM_OK);
  659.  
  660. } // end Hang_Up
  661.  
  662.