-/*
+/*
* RGB2R-C128-Kassenprogramm
* © 2007-2009 phil_fry, sECuRE, sur5r
* See LICENSE for license information
#include <peekpoke.h>
#include <stdlib.h>
#include <stdio.h>
-#include "general.h"
+#include <c128.h>
#include <stdint.h>
+#include <6502.h>
+#include <conio.h>
+
+#include "bcd2dec.h"
+#include "general.h"
+#include "globals.h"
+
+/* This file uses the CIA TOD (Complex Interface Adapter, Time of Day)
+ * for timekeeping, see https://www.c64-wiki.com/wiki/CIA and its Links section
+ * for a bit more information */
+
+/* the Time of Day PM bit is set for hours >= 12 */
+#define TOD_PM 0x80
+
+#define DAYTIME_IRQ_STACK_SIZE 32
+uint8_t daytime_irq_stack[DAYTIME_IRQ_STACK_SIZE];
+
+void update_time(void) {
+ volatile static uint8_t bcd_hour, hour, min, sec, tenth;
+
+ /* Read the hour register first to stop the clock from updating the external
+ * registers from the internal (still ticking!) CIA registers. */
+
+ bcd_hour = CIA1.tod_hour;
+
+ /* hour is >= 12 if TOD_PM is set */
+ if (bcd_hour & TOD_PM) {
+ hour = bcd2dec(bcd_hour ^ TOD_PM);
+ /* adjust for 24h clock, 12:??pm should still be 12:?? */
+ if (hour != 12) {
+ hour += 12;
+ }
+ } else {
+ hour = bcd2dec(bcd_hour);
+ }
+
+ sec = bcd2dec(CIA1.tod_sec);
+ min = bcd2dec(CIA1.tod_min);
+
+ /* MUST read tod_10 to enable the clock latch again */
+ tenth = CIA1.tod_10;
-char *get_time() {
- uint32_t h = PEEK(0x00A0) * 65536,
- m = PEEK(0x00A1) * 256,
- s = PEEK(0x00A2);
- static char buffer[9];
- BYTE hrs, min;
-
- h = (h + m + s) / 60;
- hrs = (h / 3600);
- h -= ((uint32_t)hrs * (uint32_t)3600);
- min = (h / 60);
- h -= (min * 60);
-
- sprintf(buffer, "%02d:%02d:%02d", hrs, min, (BYTE)h);
- return buffer;
+ /* it's a new day when hour wraps */
+ if (daytime.hour > hour) {
+ daytime.day++;
+ }
+
+ daytime.hour = hour;
+ daytime.min = min;
+ daytime.sec = sec;
+}
+
+char *get_time(void) {
+ static char buffer[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+ update_time();
+ sprintf(buffer, "%02d:%02d:%02d", daytime.hour, daytime.min, daytime.sec);
+ return buffer;
}
-void set_time(BYTE hrs, BYTE min, BYTE sec) {
- uint32_t added = ((uint32_t)sec + ((uint32_t)min * (uint32_t)60) + ((uint32_t)hrs * (uint32_t)3600)) * (uint32_t)60;
- uint32_t lowbit = (added & 0xFF);
- uint32_t middlebit = (added >> 8) & 0xFF;
- uint32_t highbit = (added >> 16) & 0xFF;
+/* divide by 10; put quotient in high nibble, remainder in low nibble */
+uint8_t dec2bcd(const uint8_t dec) { return (((dec / 10) << 4) | (dec % 10)); }
+
+void set_time(uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) {
+ uint8_t bcd_hour;
+
+ /* CIA TOD will always flip the PM bit
+ * when we either want to write the 0th or 12th hour.
+ * So we need to write the hour with the PM bit inverted,
+ * for the CIA to flip it again */
+ if (hour == 0) {
+ /* the 0th hour is 12am in 12h clock format, 0x12 is BCD for 12 */
+ bcd_hour = 0x12 ^ TOD_PM;
+ } else if (hour > 12) {
+ /* convert 24h clock to 12h with PM bit set */
+ bcd_hour = dec2bcd(hour - 12);
+ bcd_hour = bcd_hour ^ TOD_PM;
+ } else {
+ /* includes 12pm since the PM bit gets automatically flipped */
+ bcd_hour = dec2bcd(hour);
+ }
+
+ daytime.day = day;
+ daytime.hour = hour;
+ daytime.min = min;
+ daytime.sec = sec;
+
+ CIA1.tod_hour = bcd_hour;
+ CIA1.tod_min = dec2bcd(min);
+ CIA1.tod_sec = dec2bcd(sec);
+
+ /* set CIA1.tod_10 and program "Control Timer A" */
+ __asm__("jsr initsystime");
+}
+
+uint8_t _daytime_irq(void) {
+ static char *t;
+ static uint8_t x, y;
+ /* We are called 60 times a second. We only want to draw a clock
+ * when we are a) on the mainscreen and b) the seconds changed */
+ if (kasse_menu == MENU_MAIN && CIA1.tod_sec != daytime.sec) {
+ t = get_time();
+ x = wherex();
+ y = wherey();
+ cputsxy(70, 3, t);
+ gotoxy(x, y);
+ }
+ /* always call additional handlers */
+ return (IRQ_NOT_HANDLED);
+}
- POKE(0x00A0, (BYTE)highbit);
- POKE(0x00A1, (BYTE)middlebit);
- POKE(0x00A2, (BYTE)lowbit);
+void install_daytime_irq(void) {
+ SEI();
+ set_irq(&_daytime_irq, daytime_irq_stack, DAYTIME_IRQ_STACK_SIZE);
+ CLI();
}