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();
|
||
}
|