Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
505 lines
13 KiB
C
505 lines
13 KiB
C
// ____________________________
|
|
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
|
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
|
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
|
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
|
// Real-time clock module sample
|
|
//─────────────────────────────────────────────────────────────────────────────
|
|
|
|
//=============================================================================
|
|
// INCLUDES
|
|
//=============================================================================
|
|
#include "msxgl.h"
|
|
|
|
//=============================================================================
|
|
// DEFINES
|
|
//=============================================================================
|
|
|
|
// Digital watch parameters
|
|
#define DIGIT_Y 24
|
|
#define DIGIT_DATE 2
|
|
#define DIGIT_TIME 206
|
|
|
|
// Analog watch parameters
|
|
#define ANALOG_X 128
|
|
#define ANALOG_Y 120-8
|
|
#define ANALOG_R 70
|
|
|
|
// Library's logo
|
|
#define MSX_GL "\x01\x02\x03\x04\x05\x06"
|
|
|
|
// Functions prototype
|
|
void DisplayClock();
|
|
void UpdateClock();
|
|
void DisplaySaveData();
|
|
void UpdateSaveData();
|
|
|
|
extern const c8 g_HexChar[16];
|
|
|
|
//=============================================================================
|
|
// READ-ONLY DATA
|
|
//=============================================================================
|
|
|
|
// Trigonometric tables
|
|
#include "mathtable/mt_trigo_360.inc"
|
|
|
|
// Fonts
|
|
#include "font/font_mgl_sample6.h"
|
|
#include "font/font_mgl_digit2.h"
|
|
|
|
// Animation characters
|
|
const u8 g_ChrAnim[] = { '|', '\\', '-', '/' };
|
|
|
|
// Days of the week string table
|
|
const c8* g_DayOfWeek[] =
|
|
{
|
|
"Sunday",
|
|
"Monday",
|
|
"Tuesday",
|
|
"Wednesday",
|
|
"Thursday",
|
|
"Friday",
|
|
"Saturday",
|
|
};
|
|
|
|
// Month string table
|
|
const c8* g_Month[] =
|
|
{
|
|
"January",
|
|
"February",
|
|
"March",
|
|
"April",
|
|
"May",
|
|
"June",
|
|
"July",
|
|
"August",
|
|
"September",
|
|
"October",
|
|
"November",
|
|
"December",
|
|
};
|
|
|
|
// Valid bits table
|
|
u8 g_ValidBits[4][13] =
|
|
{
|
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12
|
|
{ 0xF, 0x7, 0xF, 0x7, 0xF, 0x3, 0x7, 0xF, 0x3, 0xF, 0x1, 0xF, 0xF, },
|
|
{ 0x0, 0x0, 0xF, 0x7, 0xF, 0x3, 0x7, 0xF, 0x3, 0x0, 0x3, 0x3, 0x0, },
|
|
{ 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, },
|
|
{ 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, },
|
|
};
|
|
|
|
//=============================================================================
|
|
// MEMORY DATA
|
|
//=============================================================================
|
|
|
|
// Current time
|
|
u8 g_Sec;
|
|
u8 g_Min;
|
|
u8 g_Hour;
|
|
|
|
// Previous time
|
|
u8 g_PrevSec;
|
|
u8 g_PrevMin;
|
|
u8 g_PrevHour;
|
|
|
|
// Save data
|
|
u8 g_SaveData[6];
|
|
|
|
callback g_Update = NULL;
|
|
|
|
//=============================================================================
|
|
// HELPER FUNCTIONS
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Update hour display
|
|
void UpdateHour()
|
|
{
|
|
// Update digital watch
|
|
if (g_Hour != g_PrevHour)
|
|
{
|
|
Print_SetPosition(DIGIT_TIME+6*0, DIGIT_Y);
|
|
Print_SetColor(0x8, 0x1);
|
|
Print_DrawText("@@");
|
|
|
|
Print_SetPosition(DIGIT_TIME+6*0, DIGIT_Y);
|
|
Print_SetColor(0x9, 0x1);
|
|
if (g_Hour < 10)
|
|
Print_DrawChar('0');
|
|
Print_DrawInt(g_Hour);
|
|
}
|
|
|
|
// Update analog watch
|
|
u16 idx = ((g_PrevHour + 9) * 30) % 360;
|
|
i16 dx = ((i16)g_Cosinus360[idx]) >> 8;
|
|
i16 dy = ((i16)g_Sinus360[idx]) >> 8;
|
|
Draw_Line(ANALOG_X, ANALOG_Y, ANALOG_X + dx, ANALOG_Y + dy, 0x1, 0);
|
|
|
|
idx = ((g_Hour + 9) * 30) % 360;
|
|
dx = ((i16)g_Cosinus360[idx]) >> 8;
|
|
dy = ((i16)g_Sinus360[idx]) >> 8;
|
|
Draw_Line(ANALOG_X, ANALOG_Y, ANALOG_X + dx, ANALOG_Y + dy, 0xF, 0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Update minute display
|
|
void UpdateMinute()
|
|
{
|
|
// Update digital watch
|
|
if (g_Min != g_PrevMin)
|
|
{
|
|
Print_SetPosition(DIGIT_TIME+6*3, DIGIT_Y);
|
|
Print_SetColor(0x8, 0x1);
|
|
Print_DrawText("@@");
|
|
|
|
Print_SetPosition(DIGIT_TIME+6*3, DIGIT_Y);
|
|
Print_SetColor(0x9, 0x1);
|
|
if (g_Min < 10)
|
|
Print_DrawChar('0');
|
|
Print_DrawInt(g_Min);
|
|
}
|
|
|
|
// Update analog watch
|
|
u16 idx = ((g_PrevMin + 45) * 6) % 360;
|
|
i16 dx = ((i16)g_Cosinus360[idx]) >> 7;
|
|
i16 dy = ((i16)g_Sinus360[idx]) >> 7;
|
|
Draw_Line(ANALOG_X, ANALOG_Y, ANALOG_X + dx, ANALOG_Y + dy, 0x1, 0);
|
|
|
|
idx = ((g_Min + 45) * 6) % 360;
|
|
dx = ((i16)g_Cosinus360[idx]) >> 7;
|
|
dy = ((i16)g_Sinus360[idx]) >> 7;
|
|
Draw_Line(ANALOG_X, ANALOG_Y, ANALOG_X + dx, ANALOG_Y + dy, 0xF, 0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Update second display
|
|
void UpdateSecond()
|
|
{
|
|
// Update digital watch
|
|
if (g_Sec != g_PrevSec)
|
|
{
|
|
Print_SetPosition(DIGIT_TIME+6*6, DIGIT_Y);
|
|
Print_SetColor(0x8, 0x1);
|
|
Print_DrawText("@@");
|
|
|
|
Print_SetPosition(DIGIT_TIME+6*6, DIGIT_Y);
|
|
Print_SetColor(0x9, 0x1);
|
|
if (g_Sec < 10)
|
|
Print_DrawChar('0');
|
|
Print_DrawInt(g_Sec);
|
|
}
|
|
|
|
// Update analog watch
|
|
u16 idx = ((g_PrevSec + 45) * 6) % 360;
|
|
i16 dx = ((i16)g_Cosinus360[idx]) >> 7;
|
|
i16 dy = ((i16)g_Sinus360[idx]) >> 7;
|
|
Draw_Line(ANALOG_X, ANALOG_Y, ANALOG_X + dx, ANALOG_Y + dy, 0x1, 0);
|
|
|
|
idx = ((g_Sec + 45) * 6) % 360;
|
|
dx = ((i16)g_Cosinus360[idx]) >> 7;
|
|
dy = ((i16)g_Sinus360[idx]) >> 7;
|
|
Draw_Line(ANALOG_X, ANALOG_Y, ANALOG_X + dx, ANALOG_Y + dy, 0x9, 0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Display the clock
|
|
void DisplayClock()
|
|
{
|
|
// Initialize print system
|
|
Print_SetBitmapFont(g_Font_MGL_Sample6);
|
|
Print_SetColor(0xFF, 0x11);
|
|
Print_Clear();
|
|
Print_SetPosition(0, 0);
|
|
Print_DrawText(MSX_GL " RTC SAMPLE - Clock");
|
|
Draw_LineH(0, 255, 12, 0xF, 0);
|
|
|
|
Print_SetPosition(0, 204);
|
|
Print_DrawText("F1:Data Save");
|
|
|
|
// Initialize the RTC module
|
|
RTC_Initialize();
|
|
RTC_Set24H(TRUE);
|
|
|
|
// Draw the static part of the analog watch
|
|
Draw_Circle(ANALOG_X, ANALOG_Y, ANALOG_R, 0xF, 0);
|
|
|
|
loop (i, 12)
|
|
{
|
|
// Analog clock hour numbers
|
|
u16 idx = (((i * 5) + 45) * 6) % 360;
|
|
i16 dx = ((i16)g_Cosinus360[idx]) >> 6;
|
|
i16 dy = ((i16)g_Sinus360[idx]) >> 6;
|
|
i16 dx2 = ((i16)g_Cosinus360[idx]) >> 10;
|
|
i16 dy2 = ((i16)g_Sinus360[idx]) >> 10;
|
|
Print_SetPosition(ANALOG_X + dx - 3 - dx2, ANALOG_Y + dy - 4 - dy2);
|
|
Print_DrawInt((i == 0) ? 12 : i);
|
|
|
|
// Analog clock hour marks
|
|
dx = ((i16)g_Cosinus360[idx]) >> 7;
|
|
dy = ((i16)g_Sinus360[idx]) >> 7;
|
|
dx2 = ((i16)g_Cosinus360[idx]) >> 9;
|
|
dy2 = ((i16)g_Sinus360[idx]) >> 9;
|
|
Draw_Line(ANALOG_X + dx + dx2, ANALOG_Y + dy + dy2 + 1, ANALOG_X + dx + 2 * dx2, ANALOG_Y + dy + 2 * dy2 + 1, 0xEE, 0);
|
|
}
|
|
|
|
// Draw the static part of the digital watch
|
|
Print_SetFont(g_Font_MGL_Digit2);
|
|
Print_SetMode(PRINT_MODE_BITMAP_TRANS);
|
|
|
|
Print_SetColor(0x8, 0x1);
|
|
Print_SetPosition(DIGIT_DATE, DIGIT_Y);
|
|
Print_DrawCharX('@', 42);
|
|
|
|
Print_SetColor(0x9, 0x1);
|
|
Print_SetPosition(DIGIT_DATE, DIGIT_Y);
|
|
Print_DrawText(g_DayOfWeek[RTC_GetDayOfWeek()]);
|
|
Print_Space();
|
|
Print_DrawText(g_Month[RTC_GetMonth() - 1]);
|
|
Print_Space();
|
|
Print_DrawInt(RTC_GetDay());
|
|
Print_Space();
|
|
Print_DrawInt(1980 + RTC_GetYear());
|
|
|
|
Print_SetPosition(DIGIT_TIME+6*2, DIGIT_Y);
|
|
Print_DrawChar(':');
|
|
Print_SetPosition(DIGIT_TIME+6*5, DIGIT_Y);
|
|
Print_DrawChar(':');
|
|
|
|
// Initialize time variables
|
|
g_Hour = 0xFF;
|
|
g_Min = 0xFF;
|
|
g_Sec = 0xFF;
|
|
|
|
g_Update = UpdateClock;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Update the clock
|
|
void UpdateClock()
|
|
{
|
|
// Update time variables
|
|
g_PrevHour = g_Hour;
|
|
g_Hour = RTC_GetHour();
|
|
g_PrevMin = g_Min;
|
|
g_Min = RTC_GetMinute();
|
|
g_PrevSec = g_Sec;
|
|
g_Sec = RTC_GetSecond();
|
|
|
|
// Wait for (linkly) the screen synchronization interruption
|
|
Halt();
|
|
|
|
// Update display
|
|
UpdateHour();
|
|
UpdateMinute();
|
|
UpdateSecond();
|
|
|
|
if (Keyboard_IsKeyPressed(KEY_F1))
|
|
DisplaySaveData();
|
|
}
|
|
|
|
extern const u32 g_AppSignature;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Draw an ID
|
|
void DrawID(const u8* data)
|
|
{
|
|
for (u8 i = 0; i < 4; ++i)
|
|
{
|
|
if ((*data >= 0x21) && (*data <= 0x7E))
|
|
Print_DrawChar(*data++);
|
|
else
|
|
Print_DrawFormat("[%2x]", *data++);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Display the save data
|
|
void DisplaySaveData()
|
|
{
|
|
// Initialize print system
|
|
Print_SetBitmapFont(g_Font_MGL_Sample6);
|
|
Print_SetColor(0xFF, 0x11);
|
|
Print_Clear();
|
|
Print_SetPosition(0, 0);
|
|
Print_DrawText(MSX_GL " RTC SAMPLE - Save");
|
|
Draw_LineH(0, 255, 12, 0xF, 0);
|
|
|
|
RTC_SetMode(RTC_MODE_BLOCK_3);
|
|
u8 type = RTC_Read(0);
|
|
|
|
//
|
|
for (u8 b = 0; b < 4; ++b)
|
|
{
|
|
Print_SetColor(0xFF, 0x11);
|
|
Print_SetPosition(22 + b * 56, 20);
|
|
Print_DrawFormat("Block#%i", b);
|
|
RTC_SetMode(b);
|
|
for (u8 r = 0; r < 13; ++r)
|
|
{
|
|
Print_SetColor(0xFF, 0x11);
|
|
if (b == 0)
|
|
{
|
|
Print_SetPosition(0, 32 + r * 8);
|
|
Print_DrawInt(r);
|
|
}
|
|
|
|
u8 col = 0xFF;
|
|
u8 v = RTC_Read(r);
|
|
if ((b == 3) && (r == 0))
|
|
{
|
|
if ((v == RTC_DATA_SAVE) || (v == RTC_DATA_SIGNSAVE))
|
|
col = 0x33;
|
|
else
|
|
col = 0x99;
|
|
}
|
|
else if ((b == 3) && ((type == RTC_DATA_SAVE) || (type == RTC_DATA_SIGNSAVE)))
|
|
col = 0x55;
|
|
else if ((b == 2) && (r == 0))
|
|
{
|
|
if (v == RTC_INIT_DONE)
|
|
col = 0x33;
|
|
else
|
|
col = 0x99;
|
|
}
|
|
else if ((b == 1) && (r >= 2) && (r <= 8) && (type == RTC_DATA_SIGNSAVE))
|
|
col = 0xBB;
|
|
|
|
Print_SetColor(col, 0x11);
|
|
Print_SetPosition(24 + b * 56, 32 + r * 8);
|
|
Print_DrawChar(g_HexChar[v]);
|
|
Print_Space();
|
|
u8 bit = 8;
|
|
for (u8 i = 0; i < 4; ++i)
|
|
{
|
|
if (g_ValidBits[b][r] & bit)
|
|
Print_SetColor(col, 0x11);
|
|
else
|
|
Print_SetColor(0xEE, 0x11);
|
|
Print_DrawChar((v & bit) ? '1' : '0');
|
|
bit >>= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
const c8* typeStr;
|
|
switch (type)
|
|
{
|
|
case RTC_DATA_TITLE: typeStr = "Title"; break;
|
|
case RTC_DATA_PASSWORD: typeStr = "Password"; break;
|
|
case RTC_DATA_PROMPT: typeStr = "Prompt"; break;
|
|
case RTC_DATA_SAVE: typeStr = "Save"; break;
|
|
case RTC_DATA_SIGNSAVE: typeStr = "SignSave"; break;
|
|
case RTC_DATA_INVALID: typeStr = "Invalid"; break;
|
|
default: typeStr = "Unknown";
|
|
}
|
|
|
|
u8 data[6];
|
|
|
|
Print_SetColor(0xFF, 0x11);
|
|
Print_SetPosition(0, 144);
|
|
Print_DrawFormat("Type: %i %s", type, typeStr);
|
|
if ((type == RTC_DATA_SAVE) || (type == RTC_DATA_SIGNSAVE))
|
|
{
|
|
bool bOK = FALSE;
|
|
if (type == RTC_DATA_SAVE)
|
|
bOK = RTC_LoadData(data);
|
|
else
|
|
bOK = RTC_LoadDataSigned(data);
|
|
Print_DrawFormat(" %2x-%2x-%2x-%2x-%2x-%2x %s", data[0], data[1], data[2], data[3], data[4], data[5], bOK ? "OK" : "NOK");
|
|
}
|
|
|
|
const u8* sign = (const u8*)&g_AppSignature;
|
|
u8 comp[4];
|
|
comp[0] = sign[0] & 0x7F;
|
|
comp[1] = sign[1] & 0x7F;
|
|
comp[2] = sign[2];
|
|
comp[3] = 0;
|
|
|
|
RTC_SetMode(RTC_MODE_BLOCK_1);
|
|
u8 cmos[4];
|
|
cmos[0] = RTC_Read(2) + (RTC_Read(3) << 4);
|
|
cmos[1] = RTC_Read(4) + (RTC_Read(6) << 4);
|
|
cmos[2] = RTC_Read(5) + (RTC_Read(7) << 2) + (RTC_Read(8) << 6);
|
|
cmos[3] = 0;
|
|
|
|
Print_SetPosition(0, 154);
|
|
Print_DrawText("Sign: ");
|
|
DrawID(sign);
|
|
Print_DrawText(" (");
|
|
DrawID(comp);
|
|
Print_DrawText(")");
|
|
|
|
Print_SetPosition(0, 164);
|
|
Print_DrawText("CMOS: ");
|
|
DrawID(cmos);
|
|
|
|
Print_SetPosition(0, 204);
|
|
Print_DrawText("F1:Clock \x83:Save \x84:Signed \x85:Erase all");
|
|
|
|
g_Update = UpdateSaveData;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Update the save data
|
|
void UpdateSaveData()
|
|
{
|
|
// Wait for (linkly) the screen synchronization interruption
|
|
Halt();
|
|
|
|
if (Keyboard_IsKeyPressed(KEY_SPACE))
|
|
{
|
|
for (u8 i = 0; i < 6; ++i)
|
|
g_SaveData[i] = (i * 2) + 1 + ((i * 2) << 4);
|
|
RTC_SaveData(g_SaveData);
|
|
DisplaySaveData();
|
|
}
|
|
if (Keyboard_IsKeyPressed(KEY_RET))
|
|
{
|
|
for (u8 i = 0; i < 6; ++i)
|
|
g_SaveData[i] = 0xBE;
|
|
RTC_SaveDataSigned(g_SaveData);
|
|
DisplaySaveData();
|
|
}
|
|
if (Keyboard_IsKeyPressed(KEY_BS))
|
|
{
|
|
for (u8 b = 0; b < 4; ++b)
|
|
{
|
|
RTC_SetMode(b);
|
|
for (u8 r = 0; r < 13; ++r)
|
|
RTC_Write(r, 0xFF);
|
|
}
|
|
DisplaySaveData();
|
|
}
|
|
|
|
if (Keyboard_IsKeyPressed(KEY_F1))
|
|
DisplayClock();
|
|
}
|
|
|
|
//=============================================================================
|
|
// MAIN LOOP
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Program entry point
|
|
void main()
|
|
{
|
|
// Initialize display system
|
|
VDP_SetMode(VDP_MODE_SCREEN5);
|
|
VDP_EnableVBlank(TRUE);
|
|
VDP_EnableSprite(FALSE);
|
|
VDP_SetLineCount(VDP_LINE_212);
|
|
VDP_SetColor(0x1);
|
|
VDP_SetPaletteEntry(8, RGB16(2, 0, 0));
|
|
VDP_SetPaletteEntry(9, RGB16(7, 0, 0));
|
|
|
|
DisplayClock();
|
|
|
|
// Main loop
|
|
while (!Keyboard_IsKeyPressed(KEY_ESC))
|
|
{
|
|
g_Update();
|
|
}
|
|
|
|
BIOS_Exit(0);
|
|
} |