diff --git a/doc/contents/datetime.tex b/doc/contents/datetime.tex new file mode 100644 index 0000000..81bff74 --- /dev/null +++ b/doc/contents/datetime.tex @@ -0,0 +1,54 @@ +\documentclass{article} +\usepackage{listings} +\usepackage{geometry} +\geometry{margin=1in} +\title{Timekeeping API} +\date{} +\begin{document} + +\maketitle + +\section*{Structure Descriptions} + +\begin{lstlisting}[language=C] + +typedef struct +{ + uint32_t hrs; + uint32_t mins; + uint32_t secs; +} timeval; + +typedef struct +{ + uint32_t day; + uint32_t month; + uint32_t year; + +} dateval; + +\end{lstlisting} + +\section*{Implementation Note} + +The number of seconds since epoch is retrieved from 926EJ-S's Real Time Clock Data Register(\textbf{RTCDR}). This is a 32 bit register, and therefore \underline{subject to the Year 2038 Problem} + +\section*{uint32_t getdate(dateval *date)} + +Fetch current date in days, months and years into \texttt{date}. Returns number of seconds since epoch. + +\section*{uint32_t gettime(timeval *time)} + +Fetch current time in hours, minutes and seconds into \texttt{time}. Returns number of seconds since epoch. + +\section*{Examples} + +\begin{lstlisting}[language=C,showstringspaces=false] +gettime(&time_struct); +puts("Current time(GMT): %d:%d:%d\n", time_struct.hrs, time_struct.mins, time_struct.secs); + +getdate(&date_struct); +puts("Current date(MM-DD-YYYY): %d-%d-%d\n", date_struct.month, date_struct.day, date_struct.year); +\end{lstlisting} + +\end{document} \ No newline at end of file diff --git a/include/datetime.h b/include/datetime.h new file mode 100644 index 0000000..329558d --- /dev/null +++ b/include/datetime.h @@ -0,0 +1,33 @@ +#ifndef DATETIME_H +#define DATETIME_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct + { + uint32_t hrs; + uint32_t mins; + uint32_t secs; + } timeval; + + typedef struct + { + uint32_t day; + uint32_t month; + uint32_t year; + + } dateval; + + uint32_t getdate(dateval *date); + uint32_t gettime(timeval *time); + +#ifdef __cplusplus +} +#endif + +#endif // DATETIME_H diff --git a/include/printf.h b/include/printf.h index 4914b38..0524ef5 100644 --- a/include/printf.h +++ b/include/printf.h @@ -10,6 +10,14 @@ extern "C" { #endif + typedef struct Format_State + { + unsigned long long num; + bool valid_format; + bool in_format; // Used to handle multi-character format specifiers + bool long_format; // %l. type specifier + } Format_State; + void puts(const char *s); void printf(char *s, ...); void getlines(char *restrict buffer, size_t length); diff --git a/kernel/kernel.c b/kernel/kernel.c index 6c725dd..f014545 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,6 +1,7 @@ #include #include +#include "datetime.h" #include "printf.h" #include "clear.h" @@ -38,6 +39,9 @@ void kernel_main(void) char input_buffer[100]; + dateval date_struct; + timeval time_struct; + bool is_running = true; while (is_running) { @@ -68,11 +72,14 @@ void kernel_main(void) case 'c': // Check for clear screen command clear(); break; - case 't': // Check for time command - printf("Current time: 12:00 PM\r\n"); // TO-DO: Implement real time check + + case 't': // Check for time command + gettime(&time_struct); + printf("Current time(GMT): %d:%d:%d\n", time_struct.hrs, time_struct.mins, time_struct.secs); break; - case 'd': // Check for date command - printf("Current date: 2023-10-01\r\n"); // TO-DO: Implement real date check + case 'd': // Check for date command + getdate(&date_struct); + printf("Current date(MM-DD-YYYY): %d-%d-%d\n", date_struct.month, date_struct.day, date_struct.year); break; default: printf("Unknown command. Type 'h' for help.\r\n"); diff --git a/user/datetime.c b/user/datetime.c new file mode 100644 index 0000000..89b470a --- /dev/null +++ b/user/datetime.c @@ -0,0 +1,64 @@ +#include +#include +#include "datetime.h" + +_Static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes"); + +#define RTCDR (*(volatile uint32_t *)0x101e8000) // RTC Register + +#define SECONDS_IN_YEAR 31556926 +#define SECONDS_IN_MONTH 2629743 +#define SECONDS_IN_DAY 86400 +#define LEAP_YEARS_BEFORE_1970 477 + +uint32_t getdate(dateval *date_struct) +{ + static uint32_t day_arr[12] = {31, 27, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // Initialize only once + + if (date_struct != NULL) + { + uint32_t since_epoch = RTCDR; + + date_struct->year = 1970 + since_epoch / SECONDS_IN_YEAR; + date_struct->month = 1 + (since_epoch / SECONDS_IN_MONTH) % 12; + + uint32_t days_since_epoch = since_epoch / SECONDS_IN_DAY; + uint32_t leap_years_since_epoch = (date_struct->year / 4) - (date_struct->year / 100) + (date_struct->year / 400) - LEAP_YEARS_BEFORE_1970; + uint32_t not_leap_years = date_struct->year - 1970 - leap_years_since_epoch; + + date_struct->day = days_since_epoch - (leap_years_since_epoch * 366) - (not_leap_years * 365); + + uint32_t is_leap_year = ((date_struct->year % 4 == 0) && (date_struct->year % 100 != 0)) || (date_struct->year % 400 == 0); + day_arr[1] += is_leap_year; // Extra day if leap year + + for (uint32_t i = 0; i < 12; i++) + { + if (date_struct->day > day_arr[i]) + { + date_struct->day -= day_arr[i]; + } + } + + day_arr[1] -= is_leap_year; // Undo the leap year effect, if any + } + + return RTCDR; +} + +uint32_t gettime(timeval *time_struct) +{ + if (time_struct != NULL) + { + uint32_t since_epoch = RTCDR; + + time_struct->secs = since_epoch % 60; + since_epoch /= 60; + + time_struct->mins = since_epoch % 60; + since_epoch /= 60; + + time_struct->hrs = since_epoch % 24; + } + + return RTCDR; +} diff --git a/user/printf.c b/user/printf.c index 9443fce..0e5ad13 100644 --- a/user/printf.c +++ b/user/printf.c @@ -6,14 +6,6 @@ // TODO: Check working of printf, all cases -typedef struct Format_State -{ - unsigned long long num; - bool valid_format; - bool in_format; // Used to handle multi-character format specifiers - bool long_format; // %l. type specifier -} Format_State; - _Static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes"); // Memory-mapped I/O registers for UART0 on QEMU versatilepb @@ -259,26 +251,139 @@ static inline char getc(void) // Function to getline from user input void getlines(char *restrict buffer, size_t length) { - size_t index = 0; + long long index = 0; + long long cursor_position = 0; + char character; + + uint8_t escape = 0; + uint8_t arrow_keys = 0; + while (index < length - 1) { character = getc(); + + if (character == '\033') // Handle Escape sequences + { + escape = 1; + continue; + } + + if (escape) + { + if (escape == 1) + { + arrow_keys = (character == 91); + } + else + { + if (arrow_keys) + { + switch (character) + { + case 'A': // Up + { + break; + } + case 'B': // Down + { + break; + } + case 'C': // Right + { + if (cursor_position < index) + { + puts("\033[C"); + cursor_position++; + } + break; + } + case 'D': // Left + { + if (cursor_position - 1 >= 0) + { + puts("\033[D"); + cursor_position--; + } + } + default: + { + break; + } + } + + arrow_keys = 0; + } + } + + escape++; + + if (escape == 3) // Escape sequence is 3 characters long + { + escape = 0; + } + + continue; + } + if (character == '\r') // Check for carriage return { break; } if ((character == '\b' || character == 0x7F) && index > 0) // Check for backspace { - index--; - putc('\b'); // Move cursor back - putc(' '); // Clear the character - putc('\b'); // Move cursor back again + if (cursor_position > 0) + { + long long initial_pos = cursor_position; + + for (long long cur = cursor_position - 1; cur < index; cur++) // Shift characters to the left + { + buffer[cur] = buffer[cur + 1]; + } + + bool cond = (index != initial_pos); + + index--; + buffer[index] = '\0'; + + cursor_position--; + + if (cond) + printf("\033[%ldC", (index - cursor_position)); + + putc('\b'); // Move cursor back + putc(' '); // Clear the character + putc('\b'); // Move cursor back again + + if (cond) + { + printf("\033[%ldD", index - cursor_position); // Analogous to the above putc sequence, but for multiple characters + printf("%s", buffer + cursor_position); + printf("\033[%ldD", index - cursor_position); + } + } } else { - buffer[index++] = character; // Store the character in the buffer - putc(character); // Echo the character back + putc(character); // Echo the character back + + long long initial_pos = cursor_position; + + for (long long cur = index; cur >= cursor_position; cur--) // Shift characters to the right + { + buffer[cur + 1] = buffer[cur]; + } + + buffer[cursor_position] = character; // Store the character in the buffer + + if (index != initial_pos) + { + puts(buffer + cursor_position + 1); + printf("\033[%ldD", index - initial_pos); + } + + cursor_position++; + index++; } } buffer[index] = '\0'; // Null-terminate the string