AmiTimeKeeper/time.c

236 lines
6.0 KiB
C

/*-
* Copyright (c) 2017-2018 Carsten Sonne Larsen <cs@innolan.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#include "time.h"
#include "mem.h"
#include <clib/alib_protos.h>
/*
* 2922 is the number of days between 1.1.1970 and 1.1.1978
* (2 leap years and 6 normal)
* 2922 * 24 * 60 * 60 = 252460800
*/
#define AMIGA_OFFSET 252460800
#define TIMER_ERROR 10
#define TIMER_OK 0
struct TimerInfo
{
bool TimerTrigged;
struct MsgPort *TimerPort;
struct timerequest *TimerIO;
};
struct Device *TimerBase = NULL;
static struct timerequest *TimerIO = NULL;
static long utcOffset = 0;
/*
* Set up pointer for timer functions.
*/
struct Device *OpenTimerBase(void)
{
LONG error;
TimerIO = (struct timerequest *)AllocMemSafe(sizeof(struct timerequest));
if (TimerIO == NULL)
{
return NULL;
}
error = OpenDevice((STRPTR)TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0);
if (error != 0)
{
FreeMemSafe(TimerIO);
TimerIO = NULL;
return NULL;
}
TimerBase = TimerIO->tr_node.io_Device;
return TimerBase;
}
void CloseTimerBase(void)
{
if (TimerBase != NULL && TimerIO != NULL)
{
CloseDevice((struct IORequest *)TimerIO);
}
if (TimerIO != NULL)
{
FreeMemSafe(TimerIO);
}
}
/*
* Open a timer device with UNIT_VBLANK.
*/
struct TimerInfo *CreateTimer(bool setTimerBase)
{
LONG error;
static const char *name = APP_SHORT_NAME " Timer Message Port";
struct TimerInfo *info = (struct TimerInfo *)AllocMemSafe(sizeof(struct TimerInfo));
if (info == NULL)
return NULL;
info->TimerPort = CreateMsgPort();
if (info->TimerPort == NULL)
{
DeleteTimer(info);
return NULL;
}
info->TimerPort->mp_Node.ln_Name = (char *)name;
info->TimerPort->mp_Node.ln_Pri = 0;
info->TimerIO = (struct timerequest *)CreateExtIO(info->TimerPort, sizeof(struct timerequest));
if (info->TimerIO == NULL)
{
DeleteTimer(info);
return NULL;
}
error = OpenDevice(
(STRPTR)TIMERNAME, UNIT_MICROHZ,
(struct IORequest *)info->TimerIO, 0);
if (error != 0)
{
DeleteTimer(info);
return NULL;
}
return info;
}
void SetTimer(struct TimerInfo *info)
{
info->TimerIO->tr_node.io_Command = TR_ADDREQUEST;
info->TimerIO->tr_time.tv_secs = Globals->Settings->Interval / 1000;
info->TimerIO->tr_time.tv_micro = Globals->Settings->Interval % 1000;
SendIO((struct IORequest *)info->TimerIO);
info->TimerTrigged = true;
}
ULONG GetTimerSigMask(struct TimerInfo *info)
{
return (1 << info->TimerPort->mp_SigBit);
}
void DeleteTimer(struct TimerInfo *info)
{
if (info->TimerIO != NULL)
{
AbortIO((struct IORequest *)info->TimerIO);
if (info->TimerTrigged)
{
WaitIO((struct IORequest *)info->TimerIO);
}
CloseDevice((struct IORequest *)info->TimerIO);
DeleteExtIO((struct IORequest *)info->TimerIO);
info->TimerIO = NULL;
}
if (info->TimerPort != NULL)
{
DeleteMsgPort(info->TimerPort);
}
FreeMemSafe(info);
}
void InitUtcOffset(void)
{
char timeZone[10];
int gmtoffset = Globals->Locale->loc_GMTOffset * 60;
utcOffset = gmtoffset + AMIGA_OFFSET;
GetTimeZoneText(timeZone);
LogWarning("Local time zone is %s", timeZone);
}
void GetTimeZoneText(char *text)
{
SNPrintf(text, 10, "UTC%s%ld:%02ld",
-Globals->Locale->loc_GMTOffset > 0 ? "+" : "",
(long)-Globals->Locale->loc_GMTOffset / 60,
(long)-Globals->Locale->loc_GMTOffset % 60);
}
void Unix2Amiga(struct timeval *unix, struct timeval *tv)
{
tv->tv_secs = unix->tv_secs + AMIGA_OFFSET;
tv->tv_micro = unix->tv_micro;
}
void Utc2Local(struct timeval *utc, struct timeval *tv)
{
int gmtoffset = Globals->Locale->loc_GMTOffset * 60;
tv->tv_secs = utc->tv_secs - gmtoffset;
tv->tv_micro = utc->tv_micro;
}
void GetTimeOfDay(struct timeval *tv)
{
GetSysTime(tv);
tv->tv_secs = tv->tv_secs + utcOffset;
}
void GetLocalTimeOfDay(struct timeval *tv)
{
GetSysTime(tv);
}
void SetTimeOfDay(const struct TimerInfo *info, const struct timeval *tv)
{
info->TimerIO->tr_node.io_Command = TR_SETSYSTIME;
info->TimerIO->tr_time.tv_secs = (long)tv->tv_secs - utcOffset;
info->TimerIO->tr_time.tv_micro = tv->tv_micro;
DoIO((struct IORequest *)info->TimerIO);
}
void SaveTimeOfDay(const struct timeval *tv)
{
WriteBattClock((long)tv->tv_secs - utcOffset);
}
void SystemTimeString(char *time, char *date, char *day)
{
struct DateTime dt;
DateStamp(&dt.dat_Stamp);
dt.dat_Format = FORMAT_DOS;
dt.dat_Flags = 0;
dt.dat_StrDay = (void *)day;
dt.dat_StrDate = (void *)date;
dt.dat_StrTime = (void *)time;
DateToStr(&dt);
}