ef8681.c
上传用户:sdttscl
上传日期:2010-01-04
资源大小:683k
文件大小:22k
源码类别:

Modem编程

开发平台:

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