From af85296ddb65f521f59a7a6b073ca7e33d5a6a6d Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Thu, 12 Sep 2024 01:07:41 +0200 Subject: [PATCH] Lab1 --- clock/src/ClockMain.java | 43 +++++++++++++---- clock/src/ClockThread.java | 41 ++++++++++++++++ clock/src/Monitor.java | 82 ++++++++++++++++++++++++++++++++ clock/src/NaiveTime.java | 97 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+), 8 deletions(-) create mode 100644 clock/src/ClockThread.java create mode 100644 clock/src/Monitor.java create mode 100644 clock/src/NaiveTime.java diff --git a/clock/src/ClockMain.java b/clock/src/ClockMain.java index 0e98232..66be88d 100644 --- a/clock/src/ClockMain.java +++ b/clock/src/ClockMain.java @@ -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); } } } diff --git a/clock/src/ClockThread.java b/clock/src/ClockThread.java new file mode 100644 index 0000000..a49e625 --- /dev/null +++ b/clock/src/ClockThread.java @@ -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(); + } + } + } +} \ No newline at end of file diff --git a/clock/src/Monitor.java b/clock/src/Monitor.java new file mode 100644 index 0000000..5ae402c --- /dev/null +++ b/clock/src/Monitor.java @@ -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); + } +} diff --git a/clock/src/NaiveTime.java b/clock/src/NaiveTime.java new file mode 100644 index 0000000..e1d236f --- /dev/null +++ b/clock/src/NaiveTime.java @@ -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; + } +}