ef8681.c
上传用户:lilishw
上传日期:2021-05-28
资源大小:1542k
文件大小:29k
源码类别:

Modem编程

开发平台:

Visual C++

  1. //---------------------------------------------------------------------------------------------------
  2. //  Project:-   DE8681
  3. //  Filename:-  EF8681.C
  4. //  Description:-   Socket Modem Main Routine and Interrupt Service Routine.
  5. //  Programmer:-    D.T.F   
  6. //  Version:-   3.0
  7. //  Created:-   28th February 2001
  8. //  Last modified:- 1/12/2003 (M.T)
  9. //---------------------------------------------------------------------------------------------------
  10. //  (C) Consumer Microcircuits Ltd 2002
  11. //
  12. //  This firmware was designed by:-
  13. //          Consumer Microcircuits Ltd,
  14. //          Langford, Maldon,
  15. //          ESSEX
  16. //          CM9 6WG.
  17. //  in the UK for use with CML evaluation kits only and is based on UK originated technology.
  18. //  Please contact
  19. //          sales@cmlmicro.co.uk
  20. //          +44 (0)1621 875500
  21. //  for licensing details.
  22. //---------------------------------------------------------------------------------------------------
  23. #define EF8681_C
  24. #include    "ef8681.h"
  25. __CONFIG(UNPROTECT|FOSC0|CPD|BKBUG);
  26. main()
  27. {
  28.     unsigned char tmpresult;
  29.     init_micro();           // Initialise Micro
  30.     init_ports();           // Initialise PIC Ports
  31.     init_regs();            // Initialise registers
  32.     init_sregs(0);          // Initialise S registers with Factory 0 defaults.
  33.     init_spi();             // Initialise SPI for control of CMX868 CBUS
  34.     reset_cbus();           // Perform CMX868 General Reset and clear device shadow registers
  35.     init_GPTs();            // Initialise General Purpose Timers
  36.     sci_init(19200, SCI_EIGHT);
  37.     PEIE = 1;               // Enable Peripheral Interrupts
  38.     GIE = 1;                // Enable Global Interrupts
  39.     RCIE = 1;               // Unmask receiver interrupts
  40.     while (DTRN)            // Wait until DTRN is low, indicating PC COM port is connected
  41.         continue;
  42.     PORTB &= 0b11110111;    // Now clear DSRN to indicate DE8681 connection to PC
  43.     genmsgtopc(idmsg);      // Send id message to terminal
  44. // Initial settings
  45.     EVMODE = 1;             // Set Evaluation Mode Flag
  46.     ATCMDMODE = 1;          // Set AT Command Mode Flag
  47.     CTSN = 0;               // Clear CTSN to indicate board is ready to receive characters
  48. // Main Loop code
  49.     do
  50.     {
  51.         if(!DTRN)
  52.         {
  53.             DTRIND = 1;     // Ensures that the DTR LED is lit when Hyper Terminal 
  54.         }                   // is connected and disconnected
  55.         else
  56.         {
  57.             DTRIND = 0;
  58.         }                       
  59.         
  60.         if (BERTFLAG)       // BERT can be performed whilst off-line or in Data transfer mode
  61.         {                   // Carrier is not monitored during this test
  62.             bert();
  63.             init_GPTs();        // Initialise General Purpose Timers ready for normal use
  64.             undo_bertporta();   // Re-initialise Port A for normal use (outputs to drive LEDs)
  65.         }
  66.         if (TESTFUNC1)      // Test Function One outputs to screen the status register contents at the S19 rate
  67.         {
  68.             do
  69.             {
  70.                 testfunc1();        // Execute Test Function One
  71.             } while (!KEYABORT);    // Loop until key pushed
  72.             TESTFUNC1 = 0;          // Clear Test Function flag
  73.             KEYABORT = 0;           // Reset key abort flag
  74.         }
  75.         if (TESTFUNC2)
  76.         {
  77.             testfunc2();
  78.         }
  79.         if (ATCMDMODE && (S0 != 0)) // Check if auto answer is possible during AT command mode
  80.         {
  81.             ringdetection();        // Check for ring detect or validate ringing
  82.         }
  83.         if (LOADCHAR)
  84.         {
  85.             while (TXIE)            // Wait until all previous characters are sent to screen
  86.                 continue;
  87.             TXIE = 1;               // Enable Tx Interrupt
  88.             LOADCHAR = 0;           // Clear Load character flag
  89.         }
  90.         if (INTERPRET)
  91.         {
  92.             resmsgtopc(atcmd_interpret());          
  93.             INTERPRET = 0;
  94.             ATBUFPTR = 0x00;        // Re-initialise AT Command Buffer pointer
  95.             CTSN = 0;               // Ensure CTSN is low to allow further characters
  96.         }
  97.         if (!DATAXFER && !ATCMDMODE)
  98.         {
  99.             hndshake_init();
  100.             hook(1);                // Go off-hook
  101.             if (ANSORIG)
  102.             {
  103.                 Delay1s(S6);        // Temporary Blind Dialling always
  104.                 dial();             // Dial routine if originating
  105.             }
  106.             tmpresult = hndshake_go();
  107.             resmsgtopc(tmpresult);
  108.             if ((tmpresult == NOCARRIER) || (tmpresult == NYI))
  109.             {
  110.                 reset_cbus();       // Reset CMX868 into powersave, will cause board to go on-hook
  111.                 DCDIND = 0;         // Turn off CD LED
  112.                 DCDN = 1;           // Set DCDN line
  113.                 DATAXFER = 0;       // Abort data transfer 
  114.                 ATCMDMODE = 1;      // Revert back to AT Command Mode
  115.                 KEYABORT = 0;       // Ensure key abort flag is cleared
  116.             }
  117.         }
  118.         if (DATAXFER && !ATCMDMODE)
  119.         {
  120.             dataxfer();             // Data Transfer loop, will exit if carrier is lost
  121.                                     // or escape sequence is entered
  122.             while (TXIE)            // Ensure all outstanding rx data has been displayed before continuing 
  123.                 continue;
  124.             CTSN = 0;               // Ensure CTSN is low to allow further characters
  125.             if (!DATAXFER)
  126.             {
  127.                 resmsgtopc(NOCARRIER);      // Return No Carrier message to PC
  128.             }
  129.             else
  130.             {
  131.                 resmsgtopc(OK);         // Return OK message to PC
  132.             }
  133.         }
  134.         if (DATAXFER && (POLLTMR == 0))
  135.         {
  136.             CMXSTAT = rd16_cbus(CMXSTAT_ADDR);  // Read CMX868 Status reg and update shadow reg
  137.             if (hangup())               // If the carrier detect flag has been lost
  138.             {
  139.                 reset_cbus();       // Reset CMX868 into powersave, will cause board to go on-hook
  140.                 DCDIND = 0;         // Turn off CD LED
  141.                 DCDN = 1;           // Set DCDN line
  142.                 DATAXFER = 0;       // Abort data transfer 
  143.                 ATCMDMODE = 1;      // Revert back to AT Command Mode
  144.                 resmsgtopc(NOCARRIER);
  145.             }
  146.             POLLTMR = 20;           // Reload 20ms Rx Energy polling timer
  147.         }
  148.     } while (EVMODE);
  149. }
  150. // Response message routine using case statements
  151. // rather than array of pointers
  152. void resmsgtopc(unsigned char messnum)
  153. {
  154.     char tempbuf[24];
  155.     unsigned char i=0;
  156.     if (RESOFF)                     // Check Result Codes are required
  157.     {
  158.         return;
  159.     }
  160.     if (!WORDRES)                   // Check if number response are required
  161.     {
  162.         if (HEXOP)
  163.         {
  164.             hexnum2scrn(messnum,2,0);   // Do not send LF char
  165.         }
  166.         else
  167.         {
  168.             decnum2scrn(messnum,2,0);   // Do not send LF char
  169.         }
  170.         return;
  171.     }
  172.     switch(messnum)
  173.     {
  174.         case 0:
  175.             strcpy(tempbuf,"OK");
  176.             break;
  177.         case 1:
  178.             strcpy(tempbuf,"CONNECT");
  179.             break;
  180.         case 2:
  181.             strcpy(tempbuf,"RING");
  182.             break;
  183.         case 3:
  184.             strcpy(tempbuf,"NO CARRIER");
  185.             break;
  186.         case 4:
  187.             strcpy(tempbuf,"ERROR");
  188.             break;
  189.         case 5:
  190.             strcpy(tempbuf,"NO DIAL TONE");
  191.             break;
  192.         case 6:
  193.             strcpy(tempbuf,"BUSY");
  194.             break;
  195.         case 7:
  196.             strcpy(tempbuf,"CONNECT 2400");
  197.             break;
  198.         case 8:
  199.             strcpy(tempbuf,"CONNECT 1200");
  200.             break;
  201.         case 9:
  202.             strcpy(tempbuf,"CONNECT 600");
  203.             break;
  204.         case 10:
  205.             strcpy(tempbuf,"CONNECT 300");
  206.             break;
  207.         case 11:
  208.             strcpy(tempbuf,"CONNECT 1200/75");
  209.             break;
  210.         case 12:
  211.             strcpy(tempbuf,"CONNECT 75/1200");
  212.             break;
  213.         case 13:
  214.             strcpy(tempbuf,"CONNECT 1200/150");
  215.             break;
  216.         case 14:
  217.             strcpy(tempbuf,"CONNECT 150/1200");
  218.             break;
  219.         case 15:
  220.             strcpy(tempbuf,"NYI");
  221.             break;
  222.         default:                    // i.e. no result code
  223.             return;
  224.     }
  225.     while ( tempbuf[i] != '')
  226.     {
  227.         MSGBUF[MSGBUFLDPTR++] = tempbuf[i]; // Load Character into output buffer
  228.         MSGBUFLDPTR &= msgbufwrap;          // Wrap round buffer if necessary
  229.     
  230.         i++;                        // Point to next character from message
  231.     }
  232.     
  233.     MSGBUF[MSGBUFLDPTR++] = S3;     // Load Message Buffer with CR char
  234.     MSGBUFLDPTR &= msgbufwrap;      // Wrap round buffer if necessary
  235.     if (WORDRES)
  236.     {
  237.         MSGBUF[MSGBUFLDPTR++] = S4; // Load Message Buffer with LF char
  238.         MSGBUFLDPTR &= msgbufwrap;  // Wrap round buffer if necessary
  239.     }
  240.     TXIE = 1;       // Enable Tx Interrupt
  241.     while (TXIE)
  242.         continue;   // Wait until all characters have been sent to terminal
  243. }
  244. void genmsgtopc(unsigned char messnum)
  245. {
  246.     char tempbuf[24];
  247.     unsigned char i=0;
  248.     if (RESOFF)     // Check Result Codes are required
  249.     {
  250.         return;
  251.     }
  252.     switch(messnum)
  253.     {
  254.         case 0:
  255.             strcpy(tempbuf,"EF8681 V3.2");      // Change this string when code is modified
  256.             break;
  257.         case 1:
  258.             strcpy(tempbuf,"DE8681 Demonstration Kit");
  259.             break;
  260.         case 2:
  261.             strcpy(tempbuf,"CML UK");
  262.             break;
  263.         case 3:
  264.             strcpy(tempbuf,"CML Singapore");
  265.             break;
  266.         case 4:
  267.             strcpy(tempbuf,"CML USA");
  268.             break;
  269.         case 5:
  270.             strcpy(tempbuf,"sales@cmlmicro.com");
  271.             break;
  272.         case 6:
  273.             strcpy(tempbuf,"sg.sales@cmlmicro.com");
  274.             break;
  275.         case 7:
  276.             strcpy(tempbuf,"us.sales@cmlmicro.com");
  277.             break;
  278.         case 8:
  279.             strcpy(tempbuf,"Tel:+44(0)1621 875500");
  280.             break;
  281.         case 9:
  282.             strcpy(tempbuf,"www.cmlmicro.com");
  283.             break;
  284.         default:
  285.             return;
  286.     }
  287.     while ( tempbuf[i] != '')
  288.     {
  289.         MSGBUF[MSGBUFLDPTR++] = tempbuf[i]; // Load Character into output buffer
  290.         MSGBUFLDPTR &= msgbufwrap;          // Wrap round buffer if necessary
  291.     
  292.         i++;                                // Point to next character from message
  293.     }
  294.     
  295.     MSGBUF[MSGBUFLDPTR++] = S3;             // Load Message Buffer with CR char
  296.     MSGBUFLDPTR &= msgbufwrap;              // Wrap round buffer if necessary
  297.     if (WORDRES)
  298.     {
  299.         MSGBUF[MSGBUFLDPTR++] = S4;         // Load Message Buffer with LF char
  300.         MSGBUFLDPTR &= msgbufwrap;          // Wrap round buffer if necessary
  301.     }
  302.     TXIE = 1;                       // Enable Tx Interrupt
  303.     while (TXIE)
  304.         continue;                   // Wait until all characters have been sent to terminal
  305. }
  306. void interrupt isr(void)
  307. {
  308.     if (T0IE && T0IF)               // Check if Timer Interrupt Enabled and interrupt flag set
  309.     {
  310.         if (!BERTFLAG)
  311.         {
  312.             update_GPTs();
  313.         }
  314.         else
  315.         {
  316.             if (BERTEND)
  317.             {
  318.                 bert_txd();
  319.             }
  320.             else
  321.             {
  322.                 bert_rxd();
  323.             }
  324.         }
  325.     }
  326.     if (RCIE && RCIF)               // Check if Rx Character Interrupt Enable and Flag
  327.     {
  328.         TXDIND = 1;                 // Turn on TXD LED
  329.         GPT4 = 2;                   // LED will stay illuminated for approx. 200mS
  330.         if (DATAXFER && !ATCMDMODE)
  331.         {
  332.             rx_datachars();
  333.         }
  334.         else
  335.         {
  336.             rx_atchars();
  337.         }                
  338.     }
  339.     if (TXIE)                       // Check if Tx Character Interrupt is enabled
  340.     {
  341.         RXDIND = 1;                 // Turn on RXD LED
  342.         GPT4=2;
  343.         tx_chars();
  344.     }
  345. }
  346. void init_GPTs()
  347. {
  348.     ESCTMR = 0;                     // 50ms Escape Sequence Timer
  349.     POLLTMR = 0;                    // 1ms General Purpose Polling Timer
  350.     RDTIMEOUT = 0;                  // Ensure ring detect timeout reg is clear at start
  351.     GPT1 = 0;                       // 10ms General Purpose Timers
  352.     GPT2 = 0;
  353.     GPT3 = 0;                       // 100ms General Purpose Timers
  354.     GPT4 = 0;
  355.     GPT5 = 0;                       // 1 second General Purpose Timers
  356.     GPT6 = 0;
  357.     PS10ms = 10;                    // Initialise Prescalers
  358.     PS100ms = 10;
  359.     PS1s = 10;
  360.     ESCPS = 50;
  361.     T0CS = 0;                       // Timer increments on instruction clock
  362.     PSA=0;                          // Assign Prescaler to TMR0
  363.     PS2=0;                          // Prescaler 1:4 TMR0
  364.     PS1=0;
  365.     PS0=1;
  366.     TMR0 = 22;                      // Ideally TMR0 count should be 250 except
  367.                                     // need to account for interrupt saving code
  368.                                     // which is approximately 70us.
  369.     T0IF = 0;                       // Clear the interrupt flag
  370.     T0IE = 1;                       // Enable interrupt on TMR0 overflow
  371. }
  372. void update_GPTs()
  373. {
  374.     T0IE = 0;                       // Disable Timer interrupt
  375.     ESCPS--;                        // Decrement Escape sequence prescaler
  376.     if (POLLTMR != 0)               // Check status of General Purpose Polling Timer (1ms)
  377.     {
  378.         POLLTMR--;                  // Decrement General Purpose Polling Timer
  379.     }
  380.     if (ESCPS == 0)
  381.     {
  382.         ESCPS = 50;                 // Reload 50ms prescaler
  383.         if (ESCTMR != 0)            // Check status of Escape Sequence Timer (50ms)
  384.         {
  385.             ESCTMR--;               // Decrement Escape Sequence Timer
  386.         }
  387.     }
  388.     PS10ms--;                       // Decrement 10ms prescaler
  389.     if (PS10ms == 0)
  390.     {
  391.         PS10ms = 10;                // Reload 10ms prescaler
  392.         PS100ms--;                  // Decrement 100ms Prescaler
  393.         if (GPT1 != 0)              // Check status of General Purpose Timer 1 (10ms)
  394.         {
  395.             GPT1--;                 // Decrement General Purpose Timer 1
  396.         }
  397.         if (GPT2 != 0)              // Check status of General Purpose Timer 2 (10ms)
  398.         {
  399.             GPT2--;                 // Decrement General Purpose Timer 2
  400.         }
  401.         if (PS100ms == 0)
  402.         {
  403.             PS100ms = 10;           // Reload 100ms prescaler
  404.             PS1s--;                 // Decrement 1s Prescaler
  405.             if (CDLOSTTMR != 0)     // Check status of Carrier Detect Lost Timer (100ms)
  406.             {
  407.                 CDLOSTTMR--;        // Decrement Carrier Detect Lost Timer
  408.             }
  409.             if (RDTIMEOUT != 0)     // Check status of Ring Detect timeout reg (100ms)
  410.             {
  411.                 RDTIMEOUT--;        // Decrement Ring Detect timeout reg
  412.             }
  413.             if (GPT3 != 0)          // Check status of General Purpose Timer 3 (100ms)
  414.             {
  415.                 GPT3--;             // Decrement General Purpose Timer 3
  416.             }
  417.             if (GPT4 != 0)          // Check status of General Purpose Timer 4 (100ms)
  418.             {
  419.                 GPT4--;             // Decrement General Purpose Timer 4
  420.             }           
  421.             else
  422.             {
  423.                 if(LED_OVERRIDE)
  424.                 {       
  425.                                     // Ensures that the TXD and RXD LEDs stay illuminated
  426.                     TXDIND = 1;     // after an at@f1 command
  427.                     RXDIND = 1;             
  428.                 }
  429.                 if(!LED_OVERRIDE)
  430.                 {
  431.                     TXDIND = 0;     // Ensures that the TXD and RXD LEDs 
  432.                     RXDIND = 0;
  433.                 }       
  434.             }
  435.             
  436.             if (PS1s == 0)
  437.             {
  438.                 PS1s = 10;          // Reload 1s prescaler
  439.                 if (GPT5 != 0)      // Check status of General Purpose Timer 5 (1s)
  440.                 {
  441.                     GPT5--;         // Decrement General Purpose Timer 5
  442.                 }
  443.                 if (GPT6 != 0)      // Check status of General Purpose Timer 6 (1s)
  444.                 {
  445.                     GPT6--;         // Decrement General Purpose Timer 6
  446.                 }
  447.             }
  448.         }
  449.     }
  450.     TMR0 = 22;                      // Reload the timer (250us * 4) per interrupt
  451.                                     // Delay in interrupt saving adjusted for
  452.     T0IF = 0;                       // Clear the interrupt flag
  453.     T0IE = 1;                       // Enable Timer interrupt
  454. }
  455. void init_regs()
  456. {
  457.     unsigned char i;
  458.     for(i=0; i<48; i++)
  459.     {
  460.         ATBUF[i] = 0;               // Clear AT Command Buffer 
  461.     }
  462.         
  463.     for(i=0; i<32; i++)
  464.     {
  465.         MSGBUF[i] = 0;              // Clear Message Buffer 
  466.     }
  467.     TELNUM[0] = NUL;                // Will intially appear empty
  468.     MODEMSTAT = 0x00;               // Initially set Evaluation Mode Flag and AT Command Mode Flag
  469.     ATCMDSTAT = 0x00;               // Clear AT Command Status register
  470.     BERTSTAT = 0x00;
  471.     XFERSTAT = 0x00;
  472.     
  473.     ATBUFPTR = 0x00;                // Initialise AT Command Buffer pointer
  474.     MSGBUFLDPTR = 0x00;             // Initialise Message Buffer Load pointer
  475.     MSGBUFRDPTR = 0x00;             // Initialise Message Buffer Read pointer
  476.     DATABUFLDPTR = 0x00;            // Initialise Data Buffer Load pointer
  477.     DATABUFRDPTR = 0x00;            // Initialise Data Buffer Read pointer
  478. }
  479. void init_sregs(unsigned char settings)
  480. {
  481.     static unsigned char bank1 sreginit[2][30] ={       // Factory Profile 0
  482.         {   0,0,43,13,10,8,2,50,2,6,        // S0 to S9
  483.             7,10,20,0,138,0,0,0,30,2,       // S10 to S19
  484.             0,193,64,0,1,176,48,0,0,0},     // S20 to S29
  485.                                 // Factory Profile 1
  486.         {   5,0,43,13,10,8,2,50,2,6,        // S0 to S9
  487.             7,20,20,0,128,0,0,0,30,2,       // S10 to S19
  488.             0,193,0,0,3,176,176,0,0,0}      // S20 to S29
  489.         };
  490.     unsigned char i;
  491.     volatile unsigned char bank2 * sregptr;
  492.     if (settings <= 1)
  493.     {
  494.         sregptr = &S0;
  495.         for(i=0; i < numsregs; i++)
  496.         {
  497.             *sregptr = sreginit[settings][i];   // Load S registers with initial settings
  498.             sregptr++;
  499.         }
  500.     }
  501. }
  502. void init_micro()
  503. {
  504.     OPTION = 0x00;
  505.     STATUS = 0x00;
  506.     PIR1 = 0x00;
  507.     INTCON = 0x00;
  508.     PIE1 = 0x00;
  509. }
  510. void init_ports()
  511. {
  512.     TRISA = CONFIGPA;                   // Configure Port A
  513.     TRISB = CONFIGPB;                   // Configure Port B
  514.     TRISC = CONFIGPC;                   // Configure Port C
  515.     ADCON1 = 0x06;                      // Port A no analog i/p's, all digital.
  516.     PORTA = INITPA;                     // Initial Port A settings
  517.     PORTB = INITPB;                     // Initial Port B settings
  518.     PORTC = INITPC;                     // Initial Port C settings
  519. }
  520. void hook(unsigned char state)                  // State determines if on or off hook (State != 0 takes modem off-hook)
  521. {
  522.     if (state == 0)
  523.     {
  524.         RLYDRV_ON = 0;                  // On-Hook
  525.     }
  526.     else
  527.     {
  528.         RLYDRV_ON = 1;                  // Off-Hook
  529.     }
  530.     wr16_cbus(CMXGENCTRL_ADDR,CMXGENCTRL);          // Write General Control information to C-BUS.
  531. }
  532. void ringdetection()    // Simple crude BT or Bell Ring Detect Check.  A valid ring consists of a burst greater
  533.                         // than 300ms then no ring detect when resampled 1 sec after burst ended.
  534. {
  535.     if (POLLTMR == 0)
  536.     {
  537.         POLLTMR = 20;   // Reload 20ms Ring detect sampling interval register
  538.         if (!RDINPROG)  // Check if ringing is in progress
  539.         {
  540.             RDCNT = 0;  // Clear ring detect sample counter
  541.             CMXSTAT = rd16_cbus(CMXSTAT_ADDR);  // Read CMX868 Status reg and update shadow reg
  542.             if (RDET)   // Ring Detect Check 
  543.             {
  544.                 S1 = 0; // Clear ring count S-register
  545.                 RDCNT++;
  546.                 RDTIMEOUT = 0;      // Ensure ring detect timeout reg is clear at start
  547.                 RDINPROG = 1;       // Set flag to indicate ringing in progress
  548.                 RIN = 0;            // Clear RIN line
  549.             }
  550.         }
  551.         else
  552.         {
  553.             if (RDTIMEOUT <= 70)        // Check 8sec ring timeout timer has been running for at least 1sec
  554.             {
  555.                 CMXSTAT = rd16_cbus(CMXSTAT_ADDR);  // Read CMX868 Status reg and update shadow reg
  556.                 if (RDET)               // Ring Detect Check 
  557.                 {
  558.                     RIN = 0;            // Ensure RIN line is clear 
  559.                     if (RDCNT != 255)   // Prevent ring detect sample count reg from wrapping round
  560.                     {
  561.                         RDCNT++;
  562.                     }
  563.                 }
  564.                 else
  565.                 {
  566.                     RIN = 1;            // Set RIN line
  567.                     if (RDCNT >= 15)    // Check if ring burst exceeded 300ms
  568.                     {
  569.                         S1++;               // Increment ring count S-register
  570.                         resmsgtopc(RING);   // Send Ring message to terminal            
  571.                         if (S1 == S0)
  572.                         {
  573.                             RDINPROG = 0;   // Initialise flag ready for next auto answer
  574.                             ATCMDMODE = 0;  // Clear flag to indicate ready for handshaking
  575.                             ANSORIG = 0;    // Clear flag to indicate answering
  576.                         }
  577.                         else
  578.                         {
  579.                             RDTIMEOUT = 80; // Reload 8sec ring detect timeout timer (100ms)
  580.                             RDCNT = 0;      // Clear ring detect sample counter
  581.                         }
  582.                     }
  583.                     else
  584.                     {
  585.                         if (RDTIMEOUT == 0) // Abort ring detect validation if 8 sec timeout has occurred
  586.                         {
  587.                             RDINPROG = 0;   // Initialise flag ready for next auto answer
  588.                         }
  589.                     }
  590.                 }
  591.             }           
  592.         }
  593.     }
  594. }
  595. void dial()                 // Dial routine Tx always enabled, alternates between DTMF and Notone
  596. {
  597.     unsigned char i=0;
  598.     CMXTXMODE &= 0x0E00;        
  599.     CMXTXMODE |= 0x1000;    // Select DTMF/Tones
  600.     // Set the DTMF twist from that set in the 3 LSBs of S28
  601.     CMXTXMODE |= (S28 & 0x07) << 5;
  602.     while (TELNUM[i] != NUL)
  603.     {
  604.         if (TELNUM[i] == ',')       // Introduce delay dial sequence
  605.         {
  606.             Delay1s(S8);
  607.         }
  608.         else
  609.         {
  610.             CMXTXMODE |= 0x0010;    // Tx DTMF
  611.             switch(TELNUM[i])
  612.             {
  613.                 case 'A': case 'a':
  614.                     CMXTXMODE |= DTMF_A;
  615.                     break;
  616.                 case 'B': case 'b':
  617.                     CMXTXMODE |= DTMF_B;
  618.                     break;
  619.                 case 'C': case 'c':
  620.                     CMXTXMODE |= DTMF_C;
  621.                     break;
  622.                 case 'D': case 'd':
  623.                     CMXTXMODE |= DTMF_D;
  624.                     break;
  625.                 case '*':
  626.                     CMXTXMODE |= DTMF_star;
  627.                     break;
  628.                 case '#':
  629.                     CMXTXMODE |= DTMF_hash;
  630.                     break;
  631.                 case '0':
  632.                     CMXTXMODE |= DTMF_0;
  633.                     break;
  634.                 default:            // Numbers 1-9
  635.                     CMXTXMODE |= (TELNUM[i] - 0x30);
  636.                     break;
  637.             }
  638.             wr16_cbus(CMXTXMODE_ADDR, CMXTXMODE);
  639.             DelayMs(S11 * 10);
  640.             CMXTXMODE &= 0xFFE0;    // Turn Tone Off
  641.             wr16_cbus(CMXTXMODE_ADDR, CMXTXMODE);
  642.             DelayMs(S11 * 10);
  643.         }
  644.         i++;
  645.     }
  646. }
  647. void decnum2scrn(unsigned int value, unsigned char digits, unsigned char linefeed) // Number of digits and LF can be controlled
  648. {
  649.     unsigned int k,quot,rem;
  650.     if ((digits > 0) && (digits < 6)) 
  651.     {
  652.         rem = value;
  653.         k=1;
  654.         do
  655.         {
  656.             k *= 10;                // Multiply k by 10
  657.             digits--;               // Decrement digits value
  658.         } while (digits > 1);
  659.         do
  660.         {
  661.             quot = rem / k;
  662.             MSGBUF[MSGBUFLDPTR++] = (quot + 0x30) & 0xFF;// Load Message Buffer
  663.     
  664.             MSGBUFLDPTR &= msgbufwrap;      // Wrap round buffer if necessary
  665.             rem %= k;
  666.             k /= 10;
  667.         } while (k >= 1);
  668.     }
  669.     MSGBUF[MSGBUFLDPTR++] = S3;             // Load Message Buffer with CR Char
  670.     MSGBUFLDPTR &= msgbufwrap;              // Wrap round buffer if necessary
  671.     if (linefeed)
  672.     {
  673.         MSGBUF[MSGBUFLDPTR++] = S4;         // Load Message Buffer with LF Char
  674.         MSGBUFLDPTR &= msgbufwrap;          // Wrap round buffer if necessary
  675.     }
  676.     TXIE=1;                         // Enable TX Interrupt
  677.     while (TXIE)
  678.         continue;                   // Wait until all characters have been sent to screen
  679. }
  680. void hexnum2scrn(unsigned int wordvalue, unsigned char digits, unsigned char linefeed) // LF can be controlled
  681. {
  682.     unsigned char shift;
  683.     unsigned char k;
  684.     shift = 4 * digits;
  685.     do
  686.     {
  687.         shift = shift - 4;
  688.         k = (wordvalue >> shift) & 0x0F;
  689.         if (k <= 9)
  690.         {
  691.             MSGBUF[MSGBUFLDPTR++] = (k + 0x30) & 0xFF;  // Load Message Buffer
  692.         }
  693.         else
  694.         {
  695.             MSGBUF[MSGBUFLDPTR++] = (k + 0x37) & 0xFF;  // Load Message Buffer
  696.         }
  697.         MSGBUFLDPTR &= msgbufwrap;          // Wrap round buffer if necessary
  698.     } while (shift != 0);
  699.     MSGBUF[MSGBUFLDPTR++] = S3;             // Load Message Buffer with CR Char
  700.     MSGBUFLDPTR &= msgbufwrap;              // Wrap round buffer if necessary
  701.     if (linefeed)
  702.     {
  703.         MSGBUF[MSGBUFLDPTR++] = S4;         // Load Message Buffer with LF Char
  704.         MSGBUFLDPTR &= msgbufwrap;          // Wrap round buffer if necessary
  705.     }
  706.     TXIE=1;                         // Enable TX Interrupt
  707.     while (TXIE)
  708.         continue;                   // Wait until all characters have been sent to screen
  709. }
  710. void testfunc1()
  711. {
  712.     CMXSTAT = rd16_cbus(CMXSTAT_ADDR);          // Update CMX868 Status Shadow register
  713.     if (HEXOP)
  714.     {
  715.         hexnum2scrn(CMXSTAT,4,WORDRES);         // Send LF char if word results enabled
  716.     }
  717.     else
  718.     {
  719.         decnum2scrn(CMXSTAT,5,WORDRES);         // Send LF char if word results enabled
  720.     }
  721.     GPT1 = S19;                     // Load GPT1(10ms) with S19 value
  722.     if (GPT1 < 2)
  723.     {
  724.         GPT1 = 2;                   // Only allow 20ms minimum
  725.     }
  726.     while(GPT1 != 0)                // Continue to loop until timer has expired
  727.         continue;
  728. }
  729. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  730. // +    at@d cmd function - set 868 to output DTMF tone
  731. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  732. void testfunc2()
  733. {   
  734.     if (ACHAR)
  735.     {
  736.         // check if typed char is '1'-'9' more code efficient this way
  737.         if (ATBUF[0] < ':' && ATBUF[0] > '0')
  738.         {
  739.             setTone(ATBUF[0] - '0');
  740.         }
  741.         else
  742.         {        
  743.             // For rest of valid chars CMXTXMODE can't be calculated easily so need switch
  744.             // convert 'a'-'d' to uppercase
  745.             if (ATBUF[0] > 0x60 && ATBUF[0] < 'e')
  746.             {
  747.                 ATBUF[0] -= 0x20;
  748.             }
  749.             switch (ATBUF[0])
  750.             {       
  751.             case 'A' :
  752.                 setTone(DTMF_A);
  753.                 break;
  754.             case 'B' :
  755.                 setTone(DTMF_B);
  756.                 break;
  757.             case 'C' :
  758.                 setTone(DTMF_C);       
  759.                 break;
  760.             case 'D' : 
  761.                 setTone(DTMF_D);
  762.                 break;
  763.             case '0' :
  764.                 setTone(DTMF_0);
  765.                 break;
  766.             case '*' :
  767.                 setTone(DTMF_star);
  768.                 break;
  769.             case '#' :
  770.                 setTone(DTMF_hash);
  771.                 break;
  772.             default : 
  773.                 resmsgtopc(OK);
  774.                 reset_cbus();
  775.                 TESTFUNC2 = 0;
  776.                 break;
  777.             }
  778.         }
  779.         wr16_cbus(CMXTXMODE_ADDR, CMXTXMODE);
  780.         ACHAR = 0;
  781.     }
  782. }
  783. /*  reduces compiled code size - used by testfunc2()                       */
  784. void setTone(char tone)
  785. {
  786.     // keep the tx level, twist level but clear the
  787.     // previous DTMF character
  788.     CMXTXMODE &= 0xFFF0;
  789.     // select the new tone
  790.     CMXTXMODE |= tone; 
  791. }