Release 1.08

This commit is contained in:
Carsten Sonne Larsen 2021-01-12 22:55:34 +01:00
parent c5adeca556
commit 82fd462f87
18 changed files with 735 additions and 250 deletions

View File

@ -1,8 +1,15 @@
AmiTimeKeeper Change Log
v1.08 18.05.2019
- When using pool server cycle with prefix 0 to 3
- Display of wrong signes in time zone fixed
- Faulty log messages about settings fixed
- Timer bug causing infitive loop fixed
- Memory leak in settings window fixed
v1.07 15.02.2019
- Support commodity hotkey and popup options
- Hide advanced setting with new expert option
- Hide advanced settings with new expert option
v1.06 08.02.2019
- Adjust layout in settings window

View File

@ -42,17 +42,19 @@ string.o: compiler.h config.h string.h mem.h
time.o: compiler.h config.h time.h mem.h
val.o: compiler.h config.h state.h message.h log.h
win_main.o: compiler.h config.h message.h state.h time.h mem.h win.h
win_gad.o: compiler.h config.h message.h state.h time.h mem.h win.h
timekeeper: broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o win_main.o win_gad.o
timekeeper: broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o val.o win_main.o win_gad.o
${CC} ${CFLAGS} ${LFLAGS} -s -o TimeKeeper \
broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o win_main.o win_gad.o \
broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o val.o win_main.o win_gad.o \
${LDLIBS}
clean:
rm -f TimeKeeper broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o settings.o sntp.o state.o time.o string.o win_main.o win_gad.o TimeKeeper.map
rm -f TimeKeeper broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o settings.o sntp.o state.o time.o string.o val.o win_main.o win_gad.o TimeKeeper.map
depend:
@echo Dependencies already done

88
Manual
View File

@ -1,5 +1,5 @@
@database TimeKeeper.guide
@$VER: TimeKeeper.guide 1.06 (2019-02-08)
@$VER: TimeKeeper.guide 1.08 (2019-05-18)
@(c) 2017-2019 Carsten Sonne Larsen <cs@innolan.net>
@author Carsten Sonne Larsen
@ -32,14 +32,17 @@
@Next "Configuring the client"
AmiTimeKeeper is a small program which keeps the time right on your
machine. No installation is required.
machine. No installation is required. It is operated as a commodity
and is controlled by AmigaOS. An AmiTCP compatible TCP/IP stack is
required for AmiTimeKeeper to work.
AmiTimeKeeper is operated as a commodity and is controlled by AmigaOS.
An AmiTCP compatible TCP/IP stack is required for AmiTimeKeeper to work.
Several settings determine the behaviour. The settings are passed
either directly from the command line or by using the tool types of
an icon. Preferences can also be saved between reboots.
AmiTimeKeeper can be configured through several settings. This can be
done either directly from the command line or by using the tooltypes
of an icon. Preferences can also be saved between reboots.
The local time zone needs to be configured using Workbench preferences
or a similar tool. in regular AmigaOS this is available through the
Locale Preferences Editor.
@{"Configuring the client" Link "Configuring the client"}
@{"Using tooltypes of an icon" Link "Using tooltypes of an icon"}
@ -54,7 +57,7 @@ of an icon. Preferences can also be saved between reboots.
@Toc "Main"
@Prev "Main"
@Next "Using tooltypes of an icon"
@{b}Server Address@{ub}
@{b}Server address@{ub}
NTP servers are managed by several organizations. The pool.ntp.org
project and Network Time Foundation are probably the two most famous.
@ -72,7 +75,10 @@ the address should be ch.pool.ntp.org.
Network Time Foundation has a website on http://support.ntp.org/
The pool.ntp.org project website is located at https://www.ntppool.org/
@{b}Server Port@{ub}
Pool server addresses will automatically be prefixed with 0, 1, 2 or 3
in order to lower the risk of choosing a none-responsive server.
@{b}Server port@{ub}
NTP servers use port 123 as default. Only under special circumstances
are the NTP server port different from 123.
@ -88,7 +94,7 @@ The requests are sent in certain intervals defined by the interval
parameter. The interval should be specified using milliseconds. One
thousand (1.000) milliseconds are equal to one second.
@{b}Threshold@{ub}
@{b}Adjustment threshold@{ub}
Due to the accuracy of NTP servers and the nature of Amiga CPUs it does
not make sense to adjust the Amiga clock on every response from the NTP
@ -97,13 +103,20 @@ The amount of accepted inaccuracy is set using the threshold parameter.
The threshold should be specified using microsecond. One million
microseconds (1.000.000) are equal to one second.
@{b}Read Only@{ub}
@{b}Read only@{ub}
It is possible to send request to the NTP server without setting the
Amiga hardware clock. This option can be handy when debugging time zone
setup and other time related parameters.
@{b}Connection Timeout@{ub}
@{b}Expert mode@{ub}
Advanced settings are hidden from the settings windown when expert mode
is not enabled. The advanced settings are server port, interval between
requests, adjustment threshold, connection timeout, verbosity level and
commodity priority.
@{b}Connection timeout@{ub}
In some cases, a connection to the NTP server cannot be established or
the NTP server simply does respond. To avoid an infinitive wait for a
@ -111,7 +124,7 @@ response the connection will instead make a time out. The timeout
interval should be specified using milliseconds. One thousand (1.000)
milliseconds are equal to one second.
@{b}Verbosity@{ub}
@{b}Verbosity level@{ub}
The level of logging can be adjusted from none to all. Expressed as a
numeric value verbose can be 0, 1, 2 or 3, where 0 is equal to none and
@ -138,13 +151,16 @@ The available tooltypes are the same as the available command line
parameters.
@{b}Parameter@{ub} | @{b}Short description@{ub}
-----------------------------------------
SERVER | Server Address
PORT | Server Port
-------------------------------------------------
SERVER | NTP server Address
PORT | NTP server Port
THRESHOLD | Adjustment threshold
INTERVAL | Interval between requests
CX_POPUP | Show settings window on startup
CX_POPKEY | Settings window keyboard shortcut
CX_PRIORITY | Commodity priority
READONLY | Read only option
READONLY | Do not set clock
EXPERT | Show advanced options
TIMEOUT | Connection Timeout
VERBOSE | Log verbosity
LOGFILE | Log file location
@ -153,11 +169,13 @@ LOGFILE | Log file location
Settings can be overridden and are set in the following order:
1. Preference file
2. Icon tooltypes
3. CLI parameters
2. Icon tooltypes / CLI parameters
CLI parameters has highest precedence and will always override settings
from icon tooltypes and from the preference file.
CLI parameters and icon tooltypes has highest precedence and will
always override settings from the preference file.
Settings from icon tooltypes are used when starting from Workbench.
Settings from CLI are used only when starting from shell.
@EndNode
@ -174,6 +192,8 @@ ENVARC:timekeeper.prefs
Depending on the setup the content of timekeeper.prefs could be:
CX_POPUP=NO
CX_POPKEY=lshift control t
CX_PRIORITY=25
THRESHOLD=1000000
SERVER=de.pool.ntp.org
@ -181,7 +201,8 @@ PORT=123
TIMEOUT=5000
INTERVAL=17500
VERBOSE=3
READONLY=0
READONLY=NO
EXPERT=NO
LOGFILE=RAM:log
The preference file should not be edited under normal circumstances.
@ -189,7 +210,7 @@ The preference file should not be edited under normal circumstances.
@{b}Caveats@{ub}
If LOGFILE is set in the preference file, no messages will be emitted
to screen (unless overridden by CLI or Icon tooltype with LOGFILE=NO).
to screen (unless overridden by CLI or icon tooltype with LOGFILE=NO).
@EndNode
@ -198,10 +219,29 @@ to screen (unless overridden by CLI or Icon tooltype with LOGFILE=NO).
@Prev "Saving preferences"
@Next "Software License"
Version 1.05, dated 06.08.2018, has proved itself to be a stable version
and has been promoted to Long Term Support. It is distributed along with
the latest version of AmiTimeKeeper.
A custom build version has been integrated into the Icaros Desktop system.
The author encourages all developers with an interest to make their own
build.
@{b}v1.08 18.05.2019@{ub}
- When using pool server cycle with prefix 0 to 3
- Display of wrong signes in time zone fixed
- Faulty log messages about settings fixed
- Timer bug causing infitive loop fixed
- Memory leak in settings window fixed
@{b}v1.07 15.02.2019@{ub}
- Support commodity hotkey and popup options
- Hide advanced settings with new expert option
@{b}v1.06 08.02.2019@{ub}
- Adjust layout in settings window
@{b}v1.05 06.08.2018@{ub}
@{b}v1.05 06.08.2018 LTS@{ub}
- Preferences can now be saved from settings window
- Time zone is shown as UTC offset in settings window
- Running multiple instances no longer create zombie processes

73
Readme Normal file
View File

@ -0,0 +1,73 @@
Short: Keep your time right
Author: Carsten Larsen (carsten.larsen@mail.com)
Uploader: Carsten Larsen (carsten.larsen@mail.com)
Type: util/cdity
Version: 1.08
Architecture: m68k-amigaos
AmiTimeKeeper is a small program which keeps the time right on your
machine. No installation is required. It is operated as a commodity
and is controlled by AmigaOS. An AmiTCP compatible TCP/IP stack is
required for AmiTimeKeeper to work.
Several settings determine the behaviour. The settings are passed
either directly from the command line or by using the tool types of
an icon. Preferences can also be saved between reboots.
The default server address is pool.ntp.org. To find another server
try visiting support.ntp.org or one of the other sites listing time
servers.
Version 1.05 has proved itself to be a stable version and has been
promoted to Long Term Support. It is distributed along with the
latest version.
A custom build version has been integrated into the Icaros Desktop
system. The author encourages all developers with an interest to
make their own build.
v1.08 18.05.2019
- When using pool server cycle with prefix 0 to 3
- Display of wrong signes in time zone fixed
- Faulty log messages about settings fixed
- Timer bug causing infitive loop fixed
- Memory leak in settings window fixed
v1.07 15.02.2019
- Support commodity hotkey and popup options
- Hide advanced settings with new expert option
v1.06 08.02.2019
- Adjust layout in settings window
v1.05 06.08.2018 LTS
- Preferences can now be saved from settings window
- Time zone is shown as UTC offset in settings window
- Running multiple instances no longer creates zombie processes
- Low water option renamed to threshold and high water option removed
- New option for sending log messages to file instead of to screen
- Some incorrect NTP log messages no longer appears
- Read-only option is now applied consistently
- Potential race condition in memory allocation fixed
- Other minor enhancements
v1.04 15.12.2017
- Default settings adjusted to comply better with AmigaOS
- Bugs in threshold settings (high/low water) fixed
- Bugs in opening and closing of libraries fixed
- New and more accurate error and log messages
v1.03 09.12.2017
- Settings window
v1.02 29.11.2017
- AROS code compliance
v1.01 28.11.2017
- Handle network disconnection
- Fix infinity timeout problem
- Support hardware clock
- Improved error messages
v1.00 26.11.2017
- First public release

View File

@ -266,7 +266,6 @@ static void ProcessMsg(void)
break;
case CXCMD_KILL:
LogInfo("Received shut down from commodity");
LogWarning("Shutting down");
StopSubProcesses();
run = false;
break;
@ -358,7 +357,6 @@ static void ProcessMsg(void)
if (sigrcvd & (1 << Globals->Broker->ShutdownSigBit))
{
LogInfo("Received shut down from setting window");
LogWarning("Shutting down");
StopSubProcesses();
run = false;
}
@ -366,7 +364,6 @@ static void ProcessMsg(void)
if (sigrcvd & SIGBREAKF_CTRL_C)
{
LogInfo("Received CTRL + C");
LogWarning("Shutting down");
StopSubProcesses();
run = false;
}

161
com.c
View File

@ -31,18 +31,26 @@
#include "sntp.h"
#include "mem.h"
#define POOLSUFFIX "pool.ntp.org"
#define POOLPORT "123"
struct AppCom
{
bool Run;
bool Restart;
bool Exited;
short TimerSigBit;
short RestartSigBit;
struct Process *Task;
struct TimerInfo *TimerInfo;
struct sntp *Client;
short RestartSigBit;
bool FirstRun;
bool SocketOpen;
int RunCount;
int FailCount;
int PoolServerNumber;
char *ServerName;
char *ServerPort;
};
static void SyncProc(void);
@ -91,8 +99,13 @@ void StartCom(void)
Globals->Syncer->Restart = false;
Globals->Syncer->Exited = false;
Globals->Syncer->FirstRun = true;
Globals->Syncer->SocketOpen = false;
Globals->Syncer->RunCount = 0;
Globals->Syncer->FailCount = 0;
Globals->Syncer->PoolServerNumber = -1;
Globals->Syncer->ServerName = NULL;
Globals->Syncer->ServerPort = NULL;
Globals->Syncer->TimerInfo = NULL;
Forbid();
Globals->Syncer->Task = CreateNewProcTags(
@ -112,6 +125,11 @@ void StartCom(void)
}
}
static ULONG GetTimerSigMask(void)
{
return (1 << Globals->Syncer->TimerSigBit);
}
static ULONG GetSntpRestartSigMask(void)
{
return (1 << Globals->Syncer->RestartSigBit);
@ -126,25 +144,12 @@ static void ComDestroy(void)
}
}
static void Sync(void)
{
char message[SETTINGMESSAGELEN];
ComOpen();
SetTimer(Globals->Syncer->TimerInfo);
SNPrintf(message, SETTINGMESSAGELEN,
"Sending next NTP request in %ld milliseconds",
Globals->Settings->Interval);
SendTraceMessage(message);
ShowStats();
Globals->Syncer->RunCount++;
}
static void SyncProc(void)
{
Globals->Syncer->TimerInfo = CreateTimer(false);
if (Globals->Syncer->TimerInfo == NULL)
Globals->Syncer->TimerSigBit = AllocSignal(-1);
if (Globals->Syncer->TimerSigBit == -1)
{
SendErrorMessage("Could not create timer for synchronizer");
SendErrorMessage("Could not allocate signal for synchronizer");
Globals->Syncer->Exited = true;
return;
}
@ -153,23 +158,37 @@ static void SyncProc(void)
if (Globals->Syncer->RestartSigBit == -1)
{
SendErrorMessage("Could not allocate signal for synchronizer");
DeleteTimer(Globals->Syncer->TimerInfo);
Globals->Syncer->Exited = true;
FreeSignal(Globals->Syncer->TimerSigBit);
return;
}
Sync();
Globals->Syncer->TimerInfo = CreateInterruptTimer(
(struct Task *)Globals->Syncer->Task,
Globals->Syncer->TimerSigBit);
if (Globals->Syncer->TimerInfo == NULL)
{
SendErrorMessage("Could not create timer for synchronizer");
Globals->Syncer->Exited = true;
FreeSignal(Globals->Syncer->TimerSigBit);
FreeSignal(Globals->Syncer->RestartSigBit);
return;
}
ComOpen();
StartInterruptTimer(Globals->Syncer->TimerInfo);
do
{
ULONG sigtime = GetTimerSigMask(Globals->Syncer->TimerInfo);
ULONG sigtime = GetTimerSigMask();
ULONG sigrest = GetSntpRestartSigMask();
ULONG sigmask = SIGBREAKF_CTRL_C | sigtime | sigrest;
ULONG sigrcvd = Wait(sigmask);
if (sigrcvd & sigtime)
{
Sync();
ComOpen();
ShowStats();
}
if (sigrcvd & sigrest)
@ -177,6 +196,7 @@ static void SyncProc(void)
ComDestroy();
Globals->Syncer->Restart = true;
ComOpen();
ShowStats();
}
if (sigrcvd & SIGBREAKF_CTRL_C)
@ -186,6 +206,8 @@ static void SyncProc(void)
} while (Globals->Syncer->Run);
ComDestroy();
StopInterruptTimer(Globals->Syncer->TimerInfo);
FreeSignal(Globals->Syncer->TimerSigBit);
FreeSignal(Globals->Syncer->RestartSigBit);
DeleteTimer(Globals->Syncer->TimerInfo);
CloseSocketLibrary();
@ -195,6 +217,18 @@ static void SyncProc(void)
SendWarningMessage("Exited synchronizer process");
}
if (Globals->Syncer->ServerName != NULL)
{
FreeMemSafe(Globals->Syncer->ServerName);
Globals->Syncer->ServerName = NULL;
}
if (Globals->Syncer->ServerPort != NULL)
{
FreeMemSafe(Globals->Syncer->ServerPort);
Globals->Syncer->ServerPort = NULL;
}
Globals->Syncer->TimerInfo = NULL;
Globals->Syncer->Task = NULL;
Globals->Syncer->Exited = true;
@ -204,10 +238,12 @@ static void ComOpen(void)
{
if (OpenSocketLibrary() != LIB_OK)
{
// Make sure socket library is open
Globals->Syncer->SocketOpen = false;
return;
}
Globals->Syncer->SocketOpen = true;
if (Globals->Syncer->FirstRun)
{
SendInfoMessage("Starting SNTP client");
@ -248,14 +284,33 @@ static void ComOpen(void)
static void ShowStats(void)
{
if (Globals->Syncer->SocketOpen)
{
char message[SETTINGMESSAGELEN];
SNPrintf(message, SETTINGMESSAGELEN,
"Sending next NTP request in %ld milliseconds",
Globals->Settings->Interval);
SendTraceMessage(message);
}
else
{
char message[SETTINGMESSAGELEN];
SNPrintf(message, SETTINGMESSAGELEN,
"Retry in %ld milliseconds",
Globals->Settings->Interval);
SendTraceMessage(message);
}
Globals->Syncer->RunCount++;
if (Globals->Syncer->RunCount % 10 == 0)
{
char message[SETTINGMESSAGELEN];
char timeString[10], dateString[10], dayString[10];
SystemTimeString(timeString, dateString, dayString);
char timeString[10], dateString[10], dayString[10], zoneString[10];
SystemTimeString(timeString, dateString, dayString, zoneString);
SNPrintf(message, SETTINGMESSAGELEN,
"Local time is %s %s %s",
dayString, dateString, timeString);
"Local time is %s %s %s%s",
dayString, dateString, timeString, zoneString);
SendInfoMessage(message);
}
@ -271,6 +326,51 @@ static void ShowStats(void)
}
}
static void ChooseServer(void)
{
char message[SETTINGMESSAGELEN];
int i;
char *server = Globals->Settings->DestinationAddress;
int len = StrLen(server);
bool isPool = EndsWith(server, POOLSUFFIX) &&
!StartsWith(server, "0.") &&
!StartsWith(server, "1.") &&
!StartsWith(server, "2.") &&
!StartsWith(server, "3.");
if (Globals->Syncer->ServerName != NULL)
{
FreeMemSafe(Globals->Syncer->ServerName);
}
if (Globals->Syncer->ServerPort != NULL)
{
FreeMemSafe(Globals->Syncer->ServerPort);
}
if (!isPool)
{
Globals->Syncer->ServerName = StrDupSafe(server);
Globals->Syncer->ServerPort = StrDupSafe(Globals->Settings->DestinationPort);
return;
}
Globals->Syncer->ServerName = (char *)AllocMemSafe(len + 3);
Globals->Syncer->ServerPort = StrDupSafe(POOLPORT);
do
{
i = RandomFast() % 4;
} while (i < 0 || i == Globals->Syncer->PoolServerNumber);
Globals->Syncer->PoolServerNumber = i;
SNPrintf(Globals->Syncer->ServerName, len + 3,
"%ld.%s", i, server);
SNPrintf(message, SETTINGMESSAGELEN,
"Choosing pool server %s", Globals->Syncer->ServerName);
SendWarningMessage(message);
}
static void ComInit(void)
{
if (Globals->Syncer->Client != NULL)
@ -279,9 +379,10 @@ static void ComInit(void)
Globals->Syncer->Client = NULL;
}
ChooseServer();
Globals->Syncer->Client = sntp_create(
Globals->Settings->DestinationAddress,
Globals->Settings->DestinationPort,
Globals->Syncer->ServerName,
Globals->Syncer->ServerPort,
NULL,
NULL);
@ -307,8 +408,8 @@ static int SyncClock(void)
SNPrintf(message, SETTINGMESSAGELEN,
"Sending request to %s:%s",
Globals->Settings->DestinationAddress,
Globals->Settings->DestinationPort);
Globals->Syncer->ServerName,
Globals->Syncer->ServerPort);
SendInfoMessage(message);
ret = sntp_send(Globals->Syncer->Client);

View File

@ -149,8 +149,8 @@ int poll(struct pollfd *, nfds_t, int);
#define APP_LONG_NAME "Amiga Time Keeper"
#endif
#define APP_VERSION "1.07"
#define APP_DATE_VERSION "1.07 (15.02.2019)"
#define APP_VERSION "1.08"
#define APP_DATE_VERSION "1.08 (18.05.2019)"
#define APP_ID APP_SHORT_NAME " " APP_DATE_VERSION
#define APP_TITLE APP_LONG_NAME " " APP_DATE_VERSION
#define APP_TITLE_VERSION APP_LONG_NAME " " APP_VERSION
@ -218,6 +218,9 @@ void HideSettingWindow(void);
int OpenLibraries(void);
void CloseLibraries(void);
/* val.c */
void SanitizeSettings(void);
/* net.c */
int OpenSocketLibrary(void);
void CloseSocketLibrary(void);

View File

@ -262,6 +262,8 @@ int OpenLibraries(void)
InitUtcOffset();
SeedRandom();
return LIB_OK;
}

6
main.c
View File

@ -148,7 +148,7 @@ static void LogStartMessage(void)
static void LogLocalTime(void)
{
char timeString[10], dateString[10], dayString[10];
SystemTimeString(timeString, dateString, dayString);
LogWarning("Local time is %s %s %s", dayString, dateString, timeString);
char timeString[10], dateString[10], dayString[10], zoneString[10];
SystemTimeString(timeString, dateString, dayString, zoneString);
LogWarning("Local time is %s %s %s%s", dayString, dateString, timeString, zoneString);
}

142
state.c
View File

@ -109,13 +109,10 @@ static const char *applyFileSettings = "Applying values from preference file";
static const char *applyCliSettings = "Applying values from CLI";
static const char *applyWbSettings = "Applying values from tooltypes";
static const char *effectiveSettings = "Listing runtime values";
static const char *settingTooLow = "%s < %ld (too low)";
static const char *settingTooHigh = "%s > %ld (too high)";
static const char *settingGreaterThan = "%s > %s";
static const char *settingChangedLong = "%s changed: %ld -> %ld";
static const char *settingChangedString = "%s changed: %s -> %s";
static const char *settingSetLong = "%s already set to %ld";
static const char *settingSetString = "%s already set to %s";
static const char *settingSetLong = "%s is already set to %ld";
static const char *settingSetString = "%s is already set to %s";
static const char *settingValueLong = "%s=%ld";
static const char *settingValueString = "%s=%s";
static const char *saveValueLong = "%s=%ld\n";
@ -236,7 +233,7 @@ static void ParseBooleanSetting(
void *value,
bool yesNo)
{
LogFoundSetting(settings->Type, SettingKeys->Popup);
LogFoundSetting(settings->Type, keyword);
// CLI switch is always a long value
if (settings->Type == CliSettingType && !yesNo)
@ -600,7 +597,7 @@ static void ApplyBooleanSetting(
}
else if (!quiet)
{
LogTrace(settingValueString, keyword, BooleanAsText(*newValue));
LogTrace(settingSetString, keyword, BooleanAsText(*newValue));
}
*curValue = *newValue;
}
@ -770,134 +767,3 @@ void ApplySettings()
}
}
static void ValidateInterval(void)
{
if (Globals->Settings->Interval < INTERVAL_MIN)
{
LogInfo(settingTooLow,
SettingKeys->Interval,
INTERVAL_MIN);
LogInfo(settingChangedLong,
SettingKeys->Interval,
Globals->Settings->Interval,
INTERVAL_MIN);
Globals->Settings->Interval = INTERVAL_MIN;
}
}
static void ValidateTimeout(void)
{
if (Globals->Settings->Timeout < TIMEOUT_MIN)
{
LogInfo(settingTooLow,
SettingKeys->Timeout,
TIMEOUT_MIN);
LogInfo(settingChangedLong,
SettingKeys->Timeout,
Globals->Settings->Timeout,
TIMEOUT_MIN);
Globals->Settings->Timeout = TIMEOUT_MIN;
}
if (Globals->Settings->Timeout > Globals->Settings->Interval)
{
LogInfo(settingGreaterThan,
SettingKeys->Timeout,
SettingKeys->Interval);
LogInfo(settingChangedLong,
SettingKeys->Timeout,
Globals->Settings->Timeout,
Globals->Settings->Interval);
Globals->Settings->Timeout = Globals->Settings->Interval;
}
if (Globals->Settings->Timeout > TIMEOUT_MAX)
{
LogInfo(settingTooHigh,
SettingKeys->Timeout,
TIMEOUT_MAX);
LogInfo(settingChangedLong,
SettingKeys->Timeout,
Globals->Settings->Timeout,
TIMEOUT_MAX);
Globals->Settings->Timeout = TIMEOUT_MAX;
}
}
static void ValidatePriority(void)
{
if (Globals->Settings->Priority < PRIORITY_MIN)
{
LogInfo(settingTooLow,
SettingKeys->Priority,
PRIORITY_MIN);
LogInfo(settingChangedLong,
SettingKeys->Priority,
Globals->Settings->Priority,
PRIORITY_MIN);
Globals->Settings->Priority = PRIORITY_MIN;
}
if (Globals->Settings->Priority > PRIORITY_MAX)
{
LogInfo(settingTooHigh,
SettingKeys->Priority,
PRIORITY_MAX);
LogInfo(settingChangedLong,
SettingKeys->Priority,
Globals->Settings->Priority,
PRIORITY_MAX);
Globals->Settings->Priority = PRIORITY_MAX;
}
}
static void ValidateThreshold(void)
{
if (Globals->Settings->Threshold < THRESHOLD_MIN)
{
LogInfo(settingTooLow,
SettingKeys->Threshold,
THRESHOLD_MIN);
LogInfo(settingChangedLong,
SettingKeys->Threshold,
Globals->Settings->Threshold,
THRESHOLD_MIN);
Globals->Settings->Threshold = THRESHOLD_MIN;
}
}
static void ValidateVerbose(void)
{
if (Globals->Settings->Verbose < VERBOSE_MIN)
{
LogInfo(settingTooLow,
SettingKeys->Verbose,
VERBOSE_MIN);
LogInfo(settingChangedLong,
SettingKeys->Verbose,
Globals->Settings->Verbose,
VERBOSE_MIN);
Globals->Settings->Verbose = VERBOSE_MIN;
}
if (Globals->Settings->Verbose > VERBOSE_MAX)
{
LogInfo(settingTooHigh,
SettingKeys->Verbose,
VERBOSE_MAX);
LogInfo(settingChangedLong,
SettingKeys->Verbose,
Globals->Settings->Verbose,
VERBOSE_MAX);
Globals->Settings->Verbose = VERBOSE_MAX;
}
}
void SanitizeSettings(void)
{
ValidateInterval();
ValidateTimeout();
ValidatePriority();
ValidateThreshold();
ValidateVerbose();
}

View File

@ -140,7 +140,6 @@ extern const struct AppSettings DefaultSettings;
void InitState(void);
void DestroyState(void);
void SanitizeSettings(void);
void ShowSettings(void);
void LoadSettings(void);
void SaveSettings(bool);

View File

@ -139,6 +139,64 @@ char *StrRChr(const char *start, const char c, int len)
return l;
}
/*
* Determine if a prefix occurs at the start of a string.
*/
bool StartsWith(const char *string, const char *prefix)
{
char *i = (char *)string;
char *j = (char *)prefix;
if (i == NULL || j == NULL)
return false;
while (*i == *j && *i != '\0' && *j != '\0')
{
i++;
j++;
}
return (*j == '\0' ? true : false);
}
/*
* Determine if a suffix occurs at the end of a string.
*/
bool EndsWith(const char *string, const char *suffix)
{
int a = 0;
int b = 0;
char *i = (char *)string;
char *j = (char *)suffix;
if (i == NULL || j == NULL)
return false;
while (*i)
{
i++;
a++;
}
while (*j)
{
j++;
b++;
}
if (b > a)
return false;
while (*i == *j && b != 0)
{
i--;
j--;
b--;
}
return (b == 0) ? true : false;
}
/*
* Convert a long to a null terminated string.
*/

View File

@ -42,6 +42,8 @@ int LongLongToStr(signed long long, char *);
int StrToLongLong(char *, unsigned long long *);
bool TryParseLong(char *, long *);
bool TryParseLongLong(char *, long long *);
bool StartsWith(const char *, const char *);
bool EndsWith(const char *, const char *);
int VSNPrintf(char *, size_t, const char *, va_list);
int SNPrintf(char *, size_t, const char *, ...);
void SplitFileName(const char *, char *, char *);

192
time.c
View File

@ -28,6 +28,7 @@
#include "time.h"
#include "mem.h"
#include <exec/interrupts.h>
#include <clib/alib_protos.h>
/*
@ -41,15 +42,26 @@
struct TimerInfo
{
bool TimerTrigged;
bool InterruptTimer;
bool TimerStarted;
bool TimerActive;
bool TimerExited;
long Interval;
long Counter;
struct MsgPort *TimerPort;
struct Interrupt *TimerInterrupt;
struct timerequest *TimerIO;
struct Task *InterruptTask;
ULONG InterruptSigBit;
};
struct Device *TimerBase = NULL;
static struct timerequest *TimerIO = NULL;
static long utcOffset = 0;
// Only one interrupt timer is allowed
struct TimerInfo *InterruptInfo;
/*
* Set up pointer for timer functions.
*/
@ -88,10 +100,119 @@ void CloseTimerBase(void)
}
}
void TimerInterruptCode(void)
{
struct TimerInfo *info = InterruptInfo;
struct timerequest *tr = (struct timerequest *)GetMsg(info->TimerPort);
if (!info->TimerActive)
{
info->TimerExited = true;
return;
}
info->Counter++;
Signal(info->InterruptTask, info->InterruptSigBit);
tr->tr_node.io_Command = TR_ADDREQUEST;
tr->tr_time.tv_secs = Globals->Settings->Interval / 1000;
tr->tr_time.tv_micro = Globals->Settings->Interval % 1000;
BeginIO((struct IORequest *)tr);
}
void StartInterruptTimer(struct TimerInfo *info)
{
info->TimerStarted = true;
info->TimerActive = true;
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;
BeginIO((struct IORequest *)info->TimerIO);
}
void StopInterruptTimer(struct TimerInfo *info)
{
info->TimerActive = false;
AbortIO((struct IORequest *)info->TimerIO);
if (info->TimerStarted)
{
WaitIO((struct IORequest *)info->TimerIO);
}
while (!info->TimerExited)
{
Delay(10);
}
}
/*
* Open a timer device with UNIT_VBLANK.
* Create a Timer device software interrupt as descibed on wiki.amigaos.net:
* https://wiki.amigaos.net/wiki/Exec_Interrupts#Software_Interrupts
* and Amiga Developer Docs 2.1, lib_examples/timersoftint.c
*/
struct TimerInfo *CreateTimer(bool setTimerBase)
struct TimerInfo *CreateInterruptTimer(struct Task *task, short sigBit)
{
LONG error;
struct TimerInfo *info = (struct TimerInfo *)AllocMemSafe(sizeof(struct TimerInfo));
if (info == NULL)
return NULL;
info->InterruptTimer = true;
info->InterruptTask = task;
info->InterruptSigBit = 1 << sigBit;
info->TimerPort = (struct MsgPort *)AllocMemSafe(sizeof(struct MsgPort));
if (info->TimerPort == NULL)
{
DeleteTimer(info);
return NULL;
}
info->TimerInterrupt = (struct Interrupt *)AllocMemSafe(sizeof(struct Interrupt));
if (info->TimerInterrupt == NULL)
{
DeleteTimer(info);
return NULL;
}
NewList(&(info->TimerPort->mp_MsgList));
info->TimerPort->mp_Node.ln_Type = NT_MSGPORT;
info->TimerPort->mp_Flags = PA_SOFTINT;
info->TimerPort->mp_SigTask = (struct Task *)info->TimerInterrupt;
info->TimerInterrupt->is_Code = TimerInterruptCode;
info->TimerInterrupt->is_Data = info;
info->TimerInterrupt->is_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;
}
// Only one interrupt timer is supported
InterruptInfo = info;
return info;
}
/*
* Open a timer device with UNIT_MICROHZ.
*/
struct TimerInfo *CreateTimer(void)
{
LONG error;
static const char *name = APP_SHORT_NAME " Timer Message Port";
@ -129,26 +250,15 @@ struct TimerInfo *CreateTimer(bool setTimerBase)
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 == NULL)
return;
if (info->TimerIO != NULL)
{
AbortIO((struct IORequest *)info->TimerIO);
if (info->TimerTrigged)
if (info->TimerStarted)
{
WaitIO((struct IORequest *)info->TimerIO);
}
@ -159,7 +269,19 @@ void DeleteTimer(struct TimerInfo *info)
if (info->TimerPort != NULL)
{
DeleteMsgPort(info->TimerPort);
if (info->InterruptTimer)
{
FreeMemSafe(info->TimerPort);
}
else
{
DeleteMsgPort(info->TimerPort);
}
}
if (info->TimerInterrupt != NULL)
{
FreeMemSafe(info->TimerInterrupt);
}
FreeMemSafe(info);
@ -170,16 +292,17 @@ void InitUtcOffset(void)
char timeZone[10];
int gmtoffset = Globals->Locale->loc_GMTOffset * 60;
utcOffset = gmtoffset + AMIGA_OFFSET;
GetTimeZoneText(timeZone);
GetTimeZoneText(timeZone, true);
LogWarning("Local time zone is %s", timeZone);
}
void GetTimeZoneText(char *text)
void GetTimeZoneText(char *text, bool includeUtc)
{
SNPrintf(text, 10, "UTC%s%ld:%02ld",
-Globals->Locale->loc_GMTOffset > 0 ? "+" : "",
(long)-Globals->Locale->loc_GMTOffset / 60,
(long)-Globals->Locale->loc_GMTOffset % 60);
SNPrintf(text, 10, "%s%s%ld:%02ld",
includeUtc ? "UTC" : "",
(Globals->Locale->loc_GMTOffset < 0L) ? "+" : "",
(long)(Globals->Locale->loc_GMTOffset / -60L),
(long)(Globals->Locale->loc_GMTOffset % -60L));
}
void Unix2Amiga(struct timeval *unix, struct timeval *tv)
@ -219,7 +342,7 @@ void SaveTimeOfDay(const struct timeval *tv)
WriteBattClock((long)tv->tv_secs - utcOffset);
}
void SystemTimeString(char *time, char *date, char *day)
void SystemTimeString(char *time, char *date, char *day, char *zone)
{
struct DateTime dt;
@ -232,4 +355,21 @@ void SystemTimeString(char *time, char *date, char *day)
dt.dat_StrTime = (void *)time;
DateToStr(&dt);
GetTimeZoneText(zone, false);
}
static int seed = 123456789;
void SeedRandom(void)
{
struct timeval tv;
GetLocalTimeOfDay(&tv);
seed = tv.tv_micro;
}
int RandomFast(void)
{
seed = (1103515245 * seed + 12345) % 0x7fffffff;
return seed;
}

13
time.h
View File

@ -33,19 +33,24 @@ struct TimerInfo;
struct Device *OpenTimerBase(void);
void CloseTimerBase(void);
struct TimerInfo *CreateTimer(bool);
struct TimerInfo *CreateTimer(void);
struct TimerInfo *CreateInterruptTimer(struct Task *, short);
void SetTimer(struct TimerInfo *);
void DeleteTimer(struct TimerInfo *);
ULONG GetTimerSigMask(struct TimerInfo *info);
void StartInterruptTimer(struct TimerInfo *);
void StopInterruptTimer(struct TimerInfo *);
void InitUtcOffset(void);
void GetTimeZoneText(char *text);
void GetTimeZoneText(char *text, bool includeUtc);
void GetTimeOfDay(struct timeval *tv);
void SetTimeOfDay(const struct TimerInfo *, const struct timeval *tv);
void SaveTimeOfDay(const struct timeval *tv);
void GetLocalTimeOfDay(struct timeval *tv);
void Unix2Amiga(struct timeval *unix, struct timeval *tv);
void Utc2Local(struct timeval *utc, struct timeval *tv);
void SystemTimeString(char *time, char *date, char *day);
void SystemTimeString(char *time, char *date, char *day, char *zone);
void SeedRandom(void);
int RandomFast(void);
#endif

191
val.c Normal file
View File

@ -0,0 +1,191 @@
/*-
* Copyright (c) 2017-2019 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 "state.h"
#include "message.h"
#include "log.h"
#include <stdarg.h>
static const char *settingChangedLong = "%s changed: %ld -> %ld";
static const char *settingTooLow = "%s < %ld (too low)";
static const char *settingTooHigh = "%s > %ld (too high)";
static const char *settingGreaterThan = "%s * 2 > %s";
static void LogValidationLine(const char *format, va_list ap)
{
char message[SETTINGMESSAGELEN];
VSNPrintf(message, SETTINGMESSAGELEN - 1, format, ap);
if (Globals->Broker->Task == NULL || FindTask(NULL) == Globals->Broker->Task)
{
LogInfo(message);
}
else
{
SendInfoMessage(message);
}
}
static void LogValidation(const char *format, ...)
{
va_list args;
va_start(args, format);
LogValidationLine(format, args);
va_end(args);
}
static void ValidateInterval(void)
{
if (Globals->Settings->Interval < INTERVAL_MIN)
{
LogValidation(settingTooLow,
SettingKeys->Interval,
INTERVAL_MIN);
LogValidation(settingChangedLong,
SettingKeys->Interval,
Globals->Settings->Interval,
INTERVAL_MIN);
Globals->Settings->Interval = INTERVAL_MIN;
}
}
static void ValidateTimeout(void)
{
if (Globals->Settings->Timeout < TIMEOUT_MIN)
{
LogValidation(settingTooLow,
SettingKeys->Timeout,
TIMEOUT_MIN);
LogValidation(settingChangedLong,
SettingKeys->Timeout,
Globals->Settings->Timeout,
TIMEOUT_MIN);
Globals->Settings->Timeout = TIMEOUT_MIN;
}
if (Globals->Settings->Timeout > Globals->Settings->Interval / 2)
{
LogValidation(settingGreaterThan,
SettingKeys->Timeout,
SettingKeys->Interval);
LogValidation(settingChangedLong,
SettingKeys->Timeout,
Globals->Settings->Timeout,
Globals->Settings->Interval / 2);
Globals->Settings->Timeout = Globals->Settings->Interval / 2;
}
if (Globals->Settings->Timeout > TIMEOUT_MAX)
{
LogValidation(settingTooHigh,
SettingKeys->Timeout,
TIMEOUT_MAX);
LogValidation(settingChangedLong,
SettingKeys->Timeout,
Globals->Settings->Timeout,
TIMEOUT_MAX);
Globals->Settings->Timeout = TIMEOUT_MAX;
}
}
static void ValidatePriority(void)
{
if (Globals->Settings->Priority < PRIORITY_MIN)
{
LogValidation(settingTooLow,
SettingKeys->Priority,
PRIORITY_MIN);
LogValidation(settingChangedLong,
SettingKeys->Priority,
Globals->Settings->Priority,
PRIORITY_MIN);
Globals->Settings->Priority = PRIORITY_MIN;
}
if (Globals->Settings->Priority > PRIORITY_MAX)
{
LogValidation(settingTooHigh,
SettingKeys->Priority,
PRIORITY_MAX);
LogValidation(settingChangedLong,
SettingKeys->Priority,
Globals->Settings->Priority,
PRIORITY_MAX);
Globals->Settings->Priority = PRIORITY_MAX;
}
}
static void ValidateThreshold(void)
{
if (Globals->Settings->Threshold < THRESHOLD_MIN)
{
LogValidation(settingTooLow,
SettingKeys->Threshold,
THRESHOLD_MIN);
LogValidation(settingChangedLong,
SettingKeys->Threshold,
Globals->Settings->Threshold,
THRESHOLD_MIN);
Globals->Settings->Threshold = THRESHOLD_MIN;
}
}
static void ValidateVerbose(void)
{
if (Globals->Settings->Verbose < VERBOSE_MIN)
{
LogValidation(settingTooLow,
SettingKeys->Verbose,
VERBOSE_MIN);
LogValidation(settingChangedLong,
SettingKeys->Verbose,
Globals->Settings->Verbose,
VERBOSE_MIN);
Globals->Settings->Verbose = VERBOSE_MIN;
}
if (Globals->Settings->Verbose > VERBOSE_MAX)
{
LogValidation(settingTooHigh,
SettingKeys->Verbose,
VERBOSE_MAX);
LogValidation(settingChangedLong,
SettingKeys->Verbose,
Globals->Settings->Verbose,
VERBOSE_MAX);
Globals->Settings->Verbose = VERBOSE_MAX;
}
}
void SanitizeSettings(void)
{
ValidateInterval();
ValidateTimeout();
ValidatePriority();
ValidateThreshold();
ValidateVerbose();
}

View File

@ -163,7 +163,6 @@ bool CreateGadgets(void)
Globals->Window->Gadgets->ServerGadget = gadget;
if (Globals->Settings->Expert)
{
// Port
@ -446,6 +445,7 @@ void SetServer(void)
FreeMemSafe(Globals->Settings->DestinationAddress);
Globals->Settings->DestinationAddress = StrDupSafe(server);
SendInfoMessage(text);
FreeMemSafe(text);
SendMessage(ATK_RESTART);
}
@ -471,6 +471,7 @@ void SetPort(void)
FreeMemSafe(Globals->Settings->DestinationPort);
Globals->Settings->DestinationPort = StrDupSafe(port);
SendInfoMessage(text);
FreeMemSafe(text);
SendMessage(ATK_RESTART);
}
@ -487,9 +488,6 @@ void SetInterval(void)
GTIN_Number, (IPTR)&value,
TAG_END);
if (value < INTERVAL_MIN)
value = INTERVAL_MIN;
if (Globals->Settings->Interval != value)
{
char *text;
@ -501,6 +499,9 @@ void SetInterval(void)
Globals->Settings->Interval = value;
text = BuildLogText(SettingKeys->Interval, oldValue, newValue);
SendInfoMessage(text);
FreeMemSafe(text);
SendMessage(ATK_RESTART);
SanitizeSettings();
}
}
@ -517,11 +518,6 @@ void SetTimeout(void)
GTIN_Number, (IPTR)&value,
TAG_END);
if (value < TIMEOUT_MIN)
value = TIMEOUT_MIN;
else if (value > TIMEOUT_MAX)
value = TIMEOUT_MAX;
if (Globals->Settings->Timeout != value)
{
char *text;
@ -533,6 +529,9 @@ void SetTimeout(void)
Globals->Settings->Timeout = value;
text = BuildLogText(SettingKeys->Timeout, oldValue, newValue);
SendInfoMessage(text);
FreeMemSafe(text);
SendMessage(ATK_RESTART);
SanitizeSettings();
}
}
@ -563,7 +562,9 @@ void SetThreshold(void)
Globals->Settings->Threshold = value;
text = BuildLogText(SettingKeys->Threshold, oldValue, newValue);
SendInfoMessage(text);
FreeMemSafe(text);
SendMessage(ATK_RESTART);
SanitizeSettings();
}
}
@ -580,11 +581,6 @@ void SetVerbose(void)
GTCY_Active, (IPTR)&value,
TAG_END);
if (value < VERBOSE_MIN)
value = VERBOSE_MIN;
else if (value > VERBOSE_MAX)
value = VERBOSE_MAX;
if (Globals->Settings->Verbose != value)
{
char *text;
@ -595,7 +591,9 @@ void SetVerbose(void)
LongToStr(value, newValue);
text = BuildLogText(SettingKeys->Verbose, oldValue, newValue);
SendInfoMessage(text);
FreeMemSafe(text);
Globals->Settings->Verbose = value;
SanitizeSettings();
}
}
@ -634,6 +632,7 @@ void SetCxPriority(void)
text = BuildLogText(SettingKeys->Priority, oldValue, newValue);
SetBrokerPriority(value);
SendInfoMessage(text);
FreeMemSafe(text);
}
}
}

View File

@ -114,7 +114,7 @@ static bool InitWindow(void)
LongToStr(Globals->Settings->Priority, Globals->Window->PriorityText);
LongLongToStr(Globals->Settings->Threshold, Globals->Window->ThresholdText);
GetTimeZoneText(Globals->Window->TimeZoneText);
GetTimeZoneText(Globals->Window->TimeZoneText, true);
return true;
}