mirror of
				https://github.com/stargieg/bacnet-stack
				synced 2025-10-26 23:35:52 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			202 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**************************************************************************
 | ||
| *
 | ||
| * Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
 | ||
| *
 | ||
| * Permission is hereby granted, free of charge, to any person obtaining
 | ||
| * a copy of this software and associated documentation files (the
 | ||
| * "Software"), to deal in the Software without restriction, including
 | ||
| * without limitation the rights to use, copy, modify, merge, publish,
 | ||
| * distribute, sublicense, and/or sell copies of the Software, and to
 | ||
| * permit persons to whom the Software is furnished to do so, subject to
 | ||
| * the following conditions:
 | ||
| *
 | ||
| * The above copyright notice and this permission notice shall be included
 | ||
| * in all copies or substantial portions of the Software.
 | ||
| *
 | ||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | ||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | ||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | ||
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | ||
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 | ||
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 | ||
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | ||
| *
 | ||
| *********************************************************************/
 | ||
| #include <stdint.h>
 | ||
| #include <stdio.h>
 | ||
| #include <dos.h>
 | ||
| 
 | ||
| /* global variable counts milliseconds */
 | ||
| volatile unsigned long Timer_Milliseconds;
 | ||
| /* MS/TP Silence Timer */
 | ||
| static volatile int SilenceTime;
 | ||
| /* counts ticks */
 | ||
| volatile unsigned long Timer_Milliseconds;
 | ||
| 
 | ||
| #define RTC_CMD_ADDR	0x70    /* RTC internal register offset goes here */
 | ||
| #define RTC_DAT_ADDR	0x71    /* RTC internal register R/W access here */
 | ||
| 
 | ||
| static uint8_t RTC_RS_Convert(
 | ||
|     uint16_t hertz)
 | ||
| {
 | ||
|     uint8_t RS = 0;
 | ||
|     /* from DS12887A datasheet
 | ||
|        SELECT BITS     tPI PERIODIC  
 | ||
|        REGISTER A      INTERRUPT    SQW OUTPUT
 | ||
|        RS3 RS2 RS1 RS0 RATE         FREQUENCY
 | ||
|        --- --- --- --- ------------ ----------
 | ||
|        0   0   0   0  None         0Hz
 | ||
|        0   0   0   1  3.90625ms    256Hz
 | ||
|        0   0   1   0  7.8125ms     128Hz
 | ||
|        0   0   1   1  122.070<EFBFBD>s    8192Hz
 | ||
|        0   1   0   0  244.141<EFBFBD>s    4096Hz
 | ||
|        0   1   0   1  488.281<EFBFBD>s    2048Hz
 | ||
|        0   1   1   0  976.5625<EFBFBD>s   1024Hz
 | ||
|        0   1   1   1  1.953125ms   512Hz
 | ||
|        1   0   0   0  3.90625ms    256Hz
 | ||
|        1   0   0   1  7.8125ms     128Hz
 | ||
|        1   0   1   0  15.625ms     64Hz
 | ||
|        1   0   1   1  31.25ms      32Hz
 | ||
|        1   1   0   0  62.5ms       16Hz
 | ||
|        1   1   0   1  125ms        8Hz
 | ||
|        1   1   1   0  250ms        4Hz
 | ||
|        1   1   1   1  500ms        2Hz    
 | ||
|      */
 | ||
|     /* FIXME: create a clever formula to replace switch */
 | ||
|     switch (hertz) {
 | ||
|         case 8192:
 | ||
|             RS = 3;
 | ||
|             break;
 | ||
|         case 4096:
 | ||
|             RS = 4;
 | ||
|             break;
 | ||
|         case 2048:
 | ||
|             RS = 5;
 | ||
|             break;
 | ||
|         case 1024:
 | ||
|             RS = 6;
 | ||
|             break;
 | ||
|         case 512:
 | ||
|             RS = 7;
 | ||
|             break;
 | ||
|         case 256:
 | ||
|             RS = 8;
 | ||
|             break;
 | ||
|         case 128:
 | ||
|             RS = 9;
 | ||
|             break;
 | ||
|         case 64:
 | ||
|             RS = 10;
 | ||
|             break;
 | ||
|         case 32:
 | ||
|             RS = 11;
 | ||
|             break;
 | ||
|         case 16:
 | ||
|             RS = 12;
 | ||
|             break;
 | ||
|         case 8:
 | ||
|             RS = 13;
 | ||
|             break;
 | ||
|         case 4:
 | ||
|             RS = 14;
 | ||
|             break;
 | ||
|         case 2:
 | ||
|             RS = 15;
 | ||
|             break;
 | ||
|         default:
 | ||
|             break;
 | ||
|     }
 | ||
| 
 | ||
|     return RS;
 | ||
| }
 | ||
| 
 | ||
| /* setting for 8192 interrupts per second 
 | ||
|    which is an interrupt every 122uS. */
 | ||
| #define INT_FREQ 8192
 | ||
| 
 | ||
| static void interrupt Timer_Interrupt_Handler(
 | ||
|     void)
 | ||
| {
 | ||
|     static uint16_t Timer_Ticks = 0;
 | ||
|     static uint16_t Elapsed_Milliseconds = 0;
 | ||
|     uint16_t milliseconds = 0;
 | ||
|     uint16_t diff = 0;
 | ||
|     uint8_t temp_reg;
 | ||
| 
 | ||
|     Timer_Ticks++;
 | ||
|     milliseconds = (Timer_Ticks * 1000) / INT_FREQ;
 | ||
|     diff = milliseconds - Elapsed_Milliseconds;
 | ||
|     if (diff >= 1) {
 | ||
|         Elapsed_Milliseconds = milliseconds;
 | ||
|         Timer_Milliseconds++;
 | ||
|         if (SilenceTime < 60000)
 | ||
|             SilenceTime++;
 | ||
|     }
 | ||
|     /* max resolution */
 | ||
|     if (Timer_Ticks >= INT_FREQ) {
 | ||
|         Timer_Ticks = 0;
 | ||
|         Elapsed_Milliseconds = 0;
 | ||
|     }
 | ||
| 
 | ||
|     /* clear interrupt */
 | ||
|     outportb(RTC_CMD_ADDR, 0x0C);       /* select RTC register C */
 | ||
|     temp_reg = inportb(RTC_DAT_ADDR);   /* read   RTC register C */
 | ||
|     /* signal end of interrupt to slave PIC */
 | ||
|     outportb(0xA0, 0x20);
 | ||
|     /* signal end of interrupt to master PIC */
 | ||
|     outportb(0x20, 0x20);
 | ||
| }
 | ||
| 
 | ||
| /* previous interrrupt vector */
 | ||
| static void interrupt(
 | ||
|     *OldVector) (
 | ||
|     );
 | ||
| 
 | ||
| void Timer_Cleanup(
 | ||
|     void)
 | ||
| {
 | ||
|     setvect(0x70, OldVector);
 | ||
| }
 | ||
| 
 | ||
| void Timer_Init(
 | ||
|     void)
 | ||
| {
 | ||
|     uint8_t RC = RTC_RS_Convert(INT_FREQ);
 | ||
| 
 | ||
|     /*  get old interrupt vector to re-install on exit */
 | ||
|     OldVector = getvect(0x70);
 | ||
|     /* disable interrupts */
 | ||
|     disable();
 | ||
|     /* set RTC int. vector for our routine */
 | ||
|     setvect(0x70, Timer_Interrupt_Handler);
 | ||
|     /* set register B with PIE enabled */
 | ||
|     outportb(RTC_CMD_ADDR, 0x0B);
 | ||
|     outportb(RTC_DAT_ADDR, 0x42);
 | ||
|     /* set register A to our frequency */
 | ||
|     outportb(RTC_CMD_ADDR, 0x0A);
 | ||
|     outportb(RTC_DAT_ADDR, (0x20 | (RC & 0x0F)));
 | ||
|     /* re-enable system interrupts */
 | ||
|     enable();
 | ||
|     atexit(Timer_Cleanup);
 | ||
| }
 | ||
| 
 | ||
| int Timer_Silence(
 | ||
|     void)
 | ||
| {
 | ||
|     uint16_t time_value;
 | ||
| 
 | ||
|     disable();
 | ||
|     time_value = SilenceTime;
 | ||
|     enable();
 | ||
| 
 | ||
|     return time_value;
 | ||
| }
 | ||
| 
 | ||
| void Timer_Silence_Reset(
 | ||
|     void)
 | ||
| {
 | ||
|     disable();
 | ||
|     SilenceTime = 0;
 | ||
|     enable();
 | ||
| }
 | 
