This commit is contained in:
Imbus 2024-09-12 01:07:41 +02:00
parent 3aca31de74
commit af85296ddb
4 changed files with 255 additions and 8 deletions

View file

@ -4,23 +4,50 @@ import clock.io.ClockInput;
import clock.io.ClockInput.UserInput;
import clock.io.ClockOutput;
// Semaphore
import java.util.concurrent.Semaphore;
public class ClockMain {
private static AlarmClockEmulator emulator = new AlarmClockEmulator();
private static ClockInput in = emulator.getInput();
private static ClockOutput out = emulator.getOutput();
static Semaphore sem = in.getSemaphore();
static Monitor monitor = new Monitor(00, 00, 00, out);
public static void main(String[] args) throws InterruptedException {
AlarmClockEmulator emulator = new AlarmClockEmulator();
ClockInput in = emulator.getInput();
ClockOutput out = emulator.getOutput();
out.displayTime(15, 2, 37); // arbitrary time: just an example
Thread clockThread = new Thread(new ClockThread(monitor, out));
while (true) {
sem.acquire();
UserInput userInput = in.getUserInput();
Choice c = userInput.choice();
Choice choice = userInput.choice();
int h = userInput.hours();
int m = userInput.minutes();
int s = userInput.seconds();
System.out.println("choice=" + c + " h=" + h + " m=" + m + " s=" + s);
switch (choice) {
case SET_TIME -> {
monitor.setTime(h, m, s);
out.displayTime(h, m, s);
// Kick off the clock thread if it's not already running
if (!clockThread.isAlive())
clockThread.start();
}
case SET_ALARM -> {
monitor.setAlarm(h, m, s);
}
case TOGGLE_ALARM -> {
monitor.toggleAlarm();
out.setAlarmIndicator(monitor.getAlarmStatus());
}
}
System.out.println("choice=" + choice + " h=" + h + " m=" + m + " s=" + s);
}
}
}

View file

@ -0,0 +1,41 @@
import clock.io.ClockOutput;
public class ClockThread implements Runnable {
long t;
long diff;
private ClockOutput out;
private Monitor monitor;
public ClockThread(Monitor monitor, ClockOutput out) {
this.out = out;
this.monitor = monitor;
t = System.currentTimeMillis();
}
@Override
public void run() {
System.out.println("ClockThread started");
while (true) {
t += 1000;
diff = t - System.currentTimeMillis();
if (diff > 0) {
try {
Thread.sleep(diff);
monitor.tick();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
NaiveTime time = monitor.getTime();
out.displayTime(time.hour(), time.min(), time.sec());
if (monitor.getAlarmStatus()) {
out.alarm();
}
}
}
}

82
clock/src/Monitor.java Normal file
View file

@ -0,0 +1,82 @@
import clock.io.ClockOutput;
import java.util.concurrent.Semaphore;
class Monitor {
private NaiveTime currentTime = new NaiveTime();
private NaiveTime alarmTime = new NaiveTime();
private boolean alarm = false;
private int beepCount = 0;
private Semaphore sema = new Semaphore(1);
private ClockOutput out;
Monitor(ClockOutput out) {
this.out = out;
}
Monitor(int h, int m, int s, ClockOutput out) {
currentTime = new NaiveTime(h, m, s);
this.out = out;
}
void setTime(int h, int m, int s) throws InterruptedException {
sema.acquire();
currentTime.set(h, m, s);
sema.release();
}
void setAlarm(int h, int m, int s) throws InterruptedException {
sema.acquire();
alarmTime = new NaiveTime(h, m, s);
sema.release();
}
void setAlarm(boolean on) {
alarm = on;
}
boolean getAlarmStatus() {
return this.alarm;
}
void toggleAlarm() {
alarm = !alarm;
}
NaiveTime getTime() {
return currentTime;
}
void tick() throws InterruptedException {
sema.acquire();
currentTime.tick();
if (currentTime.equals(alarmTime) && beepCount == 0) {
triggerAlarm();
}
// Decrement beep count each tick
if (beepCount > 0)
beepCount--;
// Stop alarm when count hits zero
if (beepCount == 0 && alarm)
stopAlarm();
sema.release();
}
void triggerAlarm() {
System.out.println("Alarm triggered!");
beepCount = 5;
this.setAlarm(true);
out.setAlarmIndicator(true);
}
void stopAlarm() {
System.out.println("Alarm stopped after 5 beeps.");
this.setAlarm(false);
out.setAlarmIndicator(false);
}
}

97
clock/src/NaiveTime.java Normal file
View file

@ -0,0 +1,97 @@
/**
* A simple class to represent time in hours, minutes, and seconds.
* This is not time zone aware, and does not account for leap seconds.
*/
public final class NaiveTime {
final static int SECONDS_IN_DAY = 60 * 60 * 24;
private int unix; // Not actually unix time
/**
* Create a new NaiveTime object with the given time
*/
public NaiveTime(int h, int m, int s) {
this.unix = h * 3600 + m * 60 + s;
}
/**
* Create a new NaiveTime object with the given time in seconds
*
* @param unix the time in seconds since midnight
*/
public NaiveTime(int unix) {
this.unix = unix;
}
/**
* Create a new NaiveTime object with the time set to midnight
*/
public NaiveTime() {
this(0, 0, 0);
}
/** Advance the NaiveTime by one second */
public void tick() {
this.unix = (this.unix + 1) % SECONDS_IN_DAY;
}
/** Set the time */
public void set(int h, int m, int s) {
// This sanity check will do for now
assert h >= 0 && h < 24;
assert m >= 0 && m < 60;
assert s >= 0 && s < 60;
// Wrap around at midnight, if for some reason above assertions fail
this.unix = (h * 3600 + m * 60 + s) % SECONDS_IN_DAY;
}
/** Returns the hour portion */
public int hour() {
return this.unix / 3600;
}
/** Set the hour */
public void setHour(int h) {
this.unix = (h * 3600) + (this.unix % 3600);
}
/** Returns the minute portion */
public int min() {
return (this.unix % 3600) / 60;
}
/** Set minute */
public void setMin(int m) {
this.unix = (this.unix / 3600) * 3600 + (m * 60) + (this.unix % 60);
}
/** Returns the current second */
public int sec() {
return this.unix % 60;
}
/** Set second */
public void setSec(int s) {
this.unix = (this.unix / 60) * 60 + s;
}
/** Equality */
public boolean equals(NaiveTime other) {
return this.unix == other.unix;
}
/** Comparison */
public boolean isBefore(NaiveTime other) {
return this.unix < other.unix;
}
/** Comparison */
public boolean isAfter(NaiveTime other) {
return this.unix > other.unix;
}
/** Returns the current time in seconds */
public int unix() {
return this.unix;
}
}