//--------------------------------------------------------------------------// /* Copyright (c) 2015 Carsten Larsen * 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 "ntimed_platform.h" #include "ntimed.h" //--------------------------------------------------------------------------// #ifdef Debug #undef Debug #endif //--------------------------------------------------------------------------// #include #include #include #include #include #include #include #include #include #include #include #include #include // -------------------------------------------------------------------------- // #ifdef AOS3 # include "clib/timezone_protos.h" # include "inline/timezone.h" #endif #ifdef AROS # include #endif // -------------------------------------------------------------------------- // // 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 AMIGAOFFSET 252460800 //--------------------------------------------------------------------------// int create_timer(); int delete_timer(); void adjust_timeval(struct timeval *tv, double offset); //--------------------------------------------------------------------------// struct Library *BattClockBase; struct Library *DOSBase = NULL; struct Library *UtilityBase = NULL; struct Library *LocaleBase = NULL; struct Library *SocketBase = NULL; struct Library *TimezoneBase = NULL; struct Locale *locale = NULL; struct Device *TimerBase = NULL; struct timerequest *request = NULL; struct timeval sync_time; char *zone_message = NULL; int validtime = 0; int limited_sync = 0; long offset = 0; //--------------------------------------------------------------------------// #ifdef AOS3 int errno; int h_errno; #endif //--------------------------------------------------------------------------// void amiga_open_error(char *name) { Put(NULL, OCX_DIAG, OPEN_ERROR, name); } void amiga_open_lib_error(char *name, int version) { Put(NULL, OCX_DIAG, OPEN_VER_ERROR, name, version); } //--------------------------------------------------------------------------// int amiga_open_libs() { if(!(DOSBase = OpenLibrary((STRPTR)DOSLIB_NAME, DOSLIB_REV))) { amiga_open_lib_error(DOSLIB_NAME, DOSLIB_REV); return 5; } if(!(LocaleBase = OpenLibrary((STRPTR)LOCALELIB_NAME, LOCALELIB_REV))) { amiga_open_lib_error(LOCALELIB_NAME, LOCALELIB_REV); return 5; } if(!(locale = OpenLocale(NULL))) { amiga_open_error("Locale"); return 10; } if(!(UtilityBase = OpenLibrary((STRPTR)UTILLIB_NAME, UTILLIB_REV))) { amiga_open_lib_error(UTILLIB_NAME, UTILLIB_REV); return 5; } if(!(BattClockBase = OpenResource((STRPTR)BATTCLOCK_NAME))) { amiga_open_error(BATTCLOCK_NAME); return 10; } if(!(SocketBase = OpenLibrary((STRPTR)BSDLIB_NAME, BSDLIB_REV))) { amiga_open_lib_error(BSDLIB_NAME, BSDLIB_REV); return 5; } if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (int)&errno, SBTM_SETVAL(SBTC_HERRNOLONGPTR), (int)&h_errno, TAG_DONE)) { amiga_open_error(BSDLIB_NAME); return 10; } if (create_timer() != 0) { amiga_open_error(TIMER_NAME); return 10; } TimezoneBase = OpenLibrary((STRPTR)TIMEZONELIB_NAME, TIMEZONELIB_REV); return 0; } //--------------------------------------------------------------------------// void amiga_close_libs() { if (TimezoneBase != NULL) { CloseLibrary(TimezoneBase); } if (request != NULL) { delete_timer(); } if (locale != NULL) { CloseLocale(locale); locale = NULL; } if (LocaleBase != NULL) { CloseLibrary(LocaleBase); LocaleBase = NULL; } if (UtilityBase != NULL) { CloseLibrary(UtilityBase); UtilityBase = NULL; } if (DOSBase != NULL) { CloseLibrary(DOSBase); DOSBase = NULL; } if (SocketBase != NULL) { CloseLibrary(SocketBase); SocketBase = NULL; } if (zone_message != NULL) { freemem(zone_message); zone_message = NULL; } } //--------------------------------------------------------------------------// void amiga_init_offset() { time_t now; struct tm tm; int gmtoffset; char *abbr; if (TimezoneBase) { now = time(NULL); localtime_r(&now, &tm); gmtoffset = tm.tm_gmtoff; abbr = (char*)tm.tm_zone; } else { gmtoffset = locale->loc_GMTOffset * 60; abbr = '\0'; } if (!zone_message) { zone_message = allocmem(40); snprintf(zone_message, 40, "Time zone is GMT %s %.f%s%s%s", (gmtoffset >= 0.0 ? "+" : "-"), fabs((float)gmtoffset / 60.0 / 60.0), (abbr != '\0' ? " (" : ""), (abbr != '\0' ? abbr : ""), (abbr != '\0' ? ")" : "") ); } offset = -gmtoffset + AMIGAOFFSET; } //--------------------------------------------------------------------------// int create_timer() { LONG error; struct MsgPort *port = CreatePort(0, 0); if (port == NULL) return 1; request = (struct timerequest*)CreateExtIO(port, sizeof(struct timerequest)); if (request == NULL) { DeletePort(port); return 1; } error = OpenDevice( (STRPTR)TIMER_NAME, UNIT_MICROHZ, (struct IORequest*)request, 0L ); if (error != 0) { delete_timer(request); return 1; } TimerBase = (struct Device*)request->tr_node.io_Device; return 0; } //--------------------------------------------------------------------------// int delete_timer() { struct MsgPort *port; if (request == NULL) return 1; port = request->tr_node.io_Message.mn_ReplyPort; if (port != 0) DeletePort(port); CloseDevice((struct IORequest*)request); DeleteExtIO((struct IORequest*)request); return 0; } //--------------------------------------------------------------------------// int gettimeofday(struct timeval *tv, struct timezone *tz) { request->tr_node.io_Command = TR_GETSYSTIME; DoIO((struct IORequest*)request); tv->tv_secs = (long)request->tr_time.tv_secs + offset; tv->tv_micro = request->tr_time.tv_micro; return 0; } int settimeofday(const struct timeval *tv, const struct timezone *tz) { request->tr_node.io_Command = TR_SETSYSTIME; request->tr_time.tv_secs = (long)tv->tv_secs - offset; request->tr_time.tv_micro = tv->tv_micro; DoIO((struct IORequest*)request); validtime++; // Make sure we are in the right timezone if (validtime == 2) { amiga_init_offset(); } return 0; } //--------------------------------------------------------------------------// void amiga_save_time(void) { time_t now; struct tm tm; struct timeval tv; int gmtoffset = 0; char *message = ""; // Assume HW clock is in GMT if timezone library is present if (TimezoneBase) { now = time(NULL); localtime_r(&now, &tm); gmtoffset = tm.tm_gmtoff; message = " GMT"; } gettimeofday(&tv, NULL); WriteBattClock((long)tv.tv_secs - offset - gmtoffset); Put(NULL, OCX_DEBUG, "Saved%s to real-time clock\n", message); } void amiga_sync_time(int seconds) { limited_sync = 1; sync_time.tv_secs = seconds; sync_time.tv_micro = 0; } int amiga_sleep_time(double dur) { ULONG sigs, timersig; struct timeval tv; tv.tv_secs = 0; tv.tv_micro = 0; if (limited_sync) { adjust_timeval(&sync_time, -dur); if ((LONG)sync_time.tv_secs < 0L) { exit(1); } } adjust_timeval(&tv, dur); request->tr_node.io_Command = TR_ADDREQUEST; request->tr_time = tv; timersig = (1L << request->tr_node.io_Message.mn_ReplyPort->mp_SigBit); SendIO((struct IORequest*)request); sigs = Wait(SIGBREAKF_CTRL_C | timersig); if (sigs & SIGBREAKF_CTRL_C) { AbortIO((struct IORequest*)request); WaitIO((struct IORequest*)request); exit(1); } return 0; } //--------------------------------------------------------------------------// void adjust_timeval(struct timeval *tv, double offset) { double d1, d2; int secs, micro; d1 = floor(offset); d2 = offset - d1; secs = tv->tv_secs + (int)d1; micro = tv->tv_micro + (int)floor(d2 * 1e6); if (micro < 0) { secs -= 1; micro += 1000000; } else if (micro >= 1000000) { secs += 1; micro -= 1000000; } tv->tv_secs = secs; tv->tv_micro = micro; } //--------------------------------------------------------------------------// #ifndef HAVE_POLL int poll(struct pollfd *pfds, nfds_t nfds, int timeout) { unsigned int i; int maxfd = -1, ret; fd_set rset,wset,xset; struct timeval timeout_tv, *tvp = NULL; if(pfds == NULL || nfds < 1) { return amiga_sleep_time(timeout / 1000); } if (timeout >= 0) { timeout_tv.tv_sec = (timeout / 1000); timeout_tv.tv_usec = (timeout % 1000) * 1000; tvp = &timeout_tv; } FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&xset); for (i = 0; i < nfds; i++) { pfds[i].revents = 0; if (pfds[i].events == 0) continue; if (pfds[i].fd > maxfd) maxfd = pfds[i].fd; if (pfds[i].events & POLLIN) FD_SET(pfds[i].fd, &rset); } #ifdef HAVE_WAITSELECT ret = WaitSelect(maxfd + 1, &rset, &wset, &xset, tvp, NULL); #else ret = select(maxfd + 1, &rset, &wset, &xset, tvp); #endif if(ret == -1) return ret; for (i = 0; i < nfds; i++) { if (pfds[i].events == 0) continue; if (FD_ISSET(pfds[i].fd, &rset)) pfds[i].revents |= POLLIN; } return ret; } #endif //--------------------------------------------------------------------------//