mirror of
https://github.com/jam422470459/EPD-nRF52-hema213.git
synced 2025-12-06 08:32:54 +08:00
add GUI emulator
This commit is contained in:
21
.github/workflows/build.yml
vendored
21
.github/workflows/build.yml
vendored
@@ -48,4 +48,23 @@ jobs:
|
|||||||
name: nrf52811_xxaa
|
name: nrf52811_xxaa
|
||||||
path: |
|
path: |
|
||||||
_build/nrf52811_xxaa.hex
|
_build/nrf52811_xxaa.hex
|
||||||
SDK/17.1.0_ddde560/components/softdevice/s112/hex/s112_nrf52_7.2.0_softdevice.hex
|
SDK/17.1.0_ddde560/components/softdevice/s112/hex/s112_nrf52_7.2.0_softdevice.hex
|
||||||
|
|
||||||
|
win32:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Install MSYS2
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
update: true
|
||||||
|
install: >-
|
||||||
|
make
|
||||||
|
mingw-w64-x86_64-gcc
|
||||||
|
- name: Build
|
||||||
|
run: make -f Makefile.win32
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: emulator
|
||||||
|
path: emulator.exe
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,6 +33,7 @@
|
|||||||
*.obj
|
*.obj
|
||||||
*.o
|
*.o
|
||||||
*.sbr
|
*.sbr
|
||||||
|
*.exe
|
||||||
|
|
||||||
# Build files
|
# Build files
|
||||||
# define exception below if needed
|
# define exception below if needed
|
||||||
|
|||||||
@@ -43,7 +43,16 @@ static void epd_gui_update(void * p_event_data, uint16_t event_size)
|
|||||||
|
|
||||||
EPD_GPIO_Init();
|
EPD_GPIO_Init();
|
||||||
epd_model_t *epd = epd_init((epd_model_id_t)p_epd->config.model_id);
|
epd_model_t *epd = epd_init((epd_model_id_t)p_epd->config.model_id);
|
||||||
DrawGUI(epd, event->timestamp, p_epd->display_mode);
|
gui_data_t data = {
|
||||||
|
.bwr = epd->bwr,
|
||||||
|
.width = epd->width,
|
||||||
|
.height = epd->height,
|
||||||
|
.timestamp = event->timestamp,
|
||||||
|
.temperature = epd->drv->read_temp(),
|
||||||
|
.voltage = EPD_ReadVoltage(),
|
||||||
|
};
|
||||||
|
DrawGUI(&data, epd->drv->write_image, p_epd->display_mode);
|
||||||
|
epd->drv->refresh();
|
||||||
EPD_GPIO_Uninit();
|
EPD_GPIO_Uninit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ static void UC8176_PowerOff(void)
|
|||||||
int8_t UC8176_Read_Temp(void)
|
int8_t UC8176_Read_Temp(void)
|
||||||
{
|
{
|
||||||
EPD_WriteCommand(CMD_TSC);
|
EPD_WriteCommand(CMD_TSC);
|
||||||
|
UC8176_WaitBusy(100);
|
||||||
return (int8_t) EPD_ReadByte();
|
return (int8_t) EPD_ReadByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
36
GUI/GUI.c
36
GUI/GUI.c
@@ -1,12 +1,8 @@
|
|||||||
#include "Adafruit_GFX.h"
|
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
#include "Lunar.h"
|
#include "Lunar.h"
|
||||||
#include "GUI.h"
|
#include "GUI.h"
|
||||||
#include "nrf_log.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define PAGE_HEIGHT ((__HEAP_SIZE / 50) - 4)
|
|
||||||
|
|
||||||
#define GFX_printf_styled(gfx, fg, bg, font, ...) \
|
#define GFX_printf_styled(gfx, fg, bg, font, ...) \
|
||||||
GFX_setTextColor(gfx, fg, bg); \
|
GFX_setTextColor(gfx, fg, bg); \
|
||||||
GFX_setFont(gfx, font); \
|
GFX_setFont(gfx, font); \
|
||||||
@@ -142,13 +138,12 @@ static void DrawTime(Adafruit_GFX *gfx, tm_t *tm, int16_t x, int16_t y, uint16_t
|
|||||||
Draw7Number(gfx, tm->tm_min, x, y, cS, GFX_BLACK, GFX_WHITE, nD);
|
Draw7Number(gfx, tm->tm_min, x, y, cS, GFX_BLACK, GFX_WHITE, nD);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawBattery(Adafruit_GFX *gfx, int16_t x, int16_t y)
|
static void DrawBattery(Adafruit_GFX *gfx, int16_t x, int16_t y, float voltage)
|
||||||
{
|
{
|
||||||
float vol = EPD_ReadVoltage();
|
uint8_t level = (uint8_t)(voltage * 100 / 4.2);
|
||||||
uint8_t level = (uint8_t)(vol * 100 / 4.2);
|
|
||||||
GFX_setCursor(gfx, x - 26, y + 9);
|
GFX_setCursor(gfx, x - 26, y + 9);
|
||||||
GFX_setFont(gfx, u8g2_font_wqy9_t_lunar);
|
GFX_setFont(gfx, u8g2_font_wqy9_t_lunar);
|
||||||
GFX_printf(gfx, "%.1fV", vol);
|
GFX_printf(gfx, "%.1fV", voltage);
|
||||||
GFX_fillRect(gfx, x, y, 20, 10, GFX_WHITE);
|
GFX_fillRect(gfx, x, y, 20, 10, GFX_WHITE);
|
||||||
GFX_drawRect(gfx, x, y, 20, 10, GFX_BLACK);
|
GFX_drawRect(gfx, x, y, 20, 10, GFX_BLACK);
|
||||||
GFX_fillRect(gfx, x + 20, y + 4, 2, 2, GFX_BLACK);
|
GFX_fillRect(gfx, x + 20, y + 4, 2, 2, GFX_BLACK);
|
||||||
@@ -162,7 +157,7 @@ static void DrawTemperature(Adafruit_GFX *gfx, int16_t x, int16_t y, int8_t temp
|
|||||||
GFX_printf(gfx, "%d℃", temp);
|
GFX_printf(gfx, "%d℃", temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawClock(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, int8_t temp)
|
static void DrawClock(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, gui_data_t *data)
|
||||||
{
|
{
|
||||||
DrawDate(gfx, 40, 36, tm);
|
DrawDate(gfx, 40, 36, tm);
|
||||||
GFX_setCursor(gfx, 40, 58);
|
GFX_setCursor(gfx, 40, 58);
|
||||||
@@ -172,8 +167,8 @@ static void DrawClock(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, int
|
|||||||
GFX_printf(gfx, "%s%s%s", Lunar_MonthLeapString[Lunar->IsLeap], Lunar_MonthString[Lunar->Month],
|
GFX_printf(gfx, "%s%s%s", Lunar_MonthLeapString[Lunar->IsLeap], Lunar_MonthString[Lunar->Month],
|
||||||
Lunar_DateString[Lunar->Date]);
|
Lunar_DateString[Lunar->Date]);
|
||||||
|
|
||||||
DrawBattery(gfx, 330, 25);
|
DrawBattery(gfx, 330, 25, data->voltage);
|
||||||
DrawTemperature(gfx, 330, 58, temp);
|
DrawTemperature(gfx, 330, 58, data->temperature);
|
||||||
|
|
||||||
GFX_drawFastHLine(gfx, 30, 68, 330, GFX_BLACK);
|
GFX_drawFastHLine(gfx, 30, 68, 330, GFX_BLACK);
|
||||||
DrawTime(gfx, tm, 70, 98, 5, 2);
|
DrawTime(gfx, tm, 70, 98, 5, 2);
|
||||||
@@ -197,24 +192,23 @@ static void DrawClock(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawGUI(epd_model_t *epd, uint32_t timestamp, display_mode_t mode)
|
void DrawGUI(gui_data_t *data, buffer_callback draw, display_mode_t mode)
|
||||||
{
|
{
|
||||||
tm_t tm = {0};
|
tm_t tm = {0};
|
||||||
struct Lunar_Date Lunar;
|
struct Lunar_Date Lunar;
|
||||||
|
|
||||||
transformTime(timestamp, &tm);
|
transformTime(data->timestamp, &tm);
|
||||||
LUNAR_SolarToLunar(&Lunar, tm.tm_year + YEAR0, tm.tm_mon + 1, tm.tm_mday);
|
LUNAR_SolarToLunar(&Lunar, tm.tm_year + YEAR0, tm.tm_mon + 1, tm.tm_mday);
|
||||||
|
|
||||||
Adafruit_GFX gfx;
|
Adafruit_GFX gfx;
|
||||||
|
|
||||||
if (epd->bwr)
|
if (data->bwr)
|
||||||
GFX_begin_3c(&gfx, epd->width, epd->height, PAGE_HEIGHT);
|
GFX_begin_3c(&gfx, data->width, data->height, PAGE_HEIGHT);
|
||||||
else
|
else
|
||||||
GFX_begin(&gfx, epd->width, epd->height, PAGE_HEIGHT);
|
GFX_begin(&gfx, data->width, data->height, PAGE_HEIGHT);
|
||||||
|
|
||||||
GFX_firstPage(&gfx);
|
GFX_firstPage(&gfx);
|
||||||
do {
|
do {
|
||||||
NRF_LOG_DEBUG("page %d\n", gfx.current_page);
|
|
||||||
GFX_fillScreen(&gfx, GFX_WHITE);
|
GFX_fillScreen(&gfx, GFX_WHITE);
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@@ -222,16 +216,12 @@ void DrawGUI(epd_model_t *epd, uint32_t timestamp, display_mode_t mode)
|
|||||||
DrawCalendar(&gfx, &tm, &Lunar);
|
DrawCalendar(&gfx, &tm, &Lunar);
|
||||||
break;
|
break;
|
||||||
case MODE_CLOCK:
|
case MODE_CLOCK:
|
||||||
DrawClock(&gfx, &tm, &Lunar, epd->drv->read_temp());
|
DrawClock(&gfx, &tm, &Lunar, data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(GFX_nextPage(&gfx, epd->drv->write_image));
|
} while(GFX_nextPage(&gfx, draw));
|
||||||
|
|
||||||
GFX_end(&gfx);
|
GFX_end(&gfx);
|
||||||
|
|
||||||
NRF_LOG_DEBUG("display start\n");
|
|
||||||
epd->drv->refresh();
|
|
||||||
NRF_LOG_DEBUG("display end\n");
|
|
||||||
}
|
}
|
||||||
|
|||||||
18
GUI/GUI.h
18
GUI/GUI.h
@@ -1,8 +1,11 @@
|
|||||||
#ifndef __GUI_H
|
#ifndef __GUI_H
|
||||||
#define __GUI_H
|
#define __GUI_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include "Adafruit_GFX.h"
|
||||||
#include "EPD_driver.h"
|
|
||||||
|
#ifndef PAGE_HEIGHT
|
||||||
|
#define PAGE_HEIGHT ((__HEAP_SIZE / 50) - 4)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MODE_NONE = 0,
|
MODE_NONE = 0,
|
||||||
@@ -10,6 +13,15 @@ typedef enum {
|
|||||||
MODE_CLOCK = 2,
|
MODE_CLOCK = 2,
|
||||||
} display_mode_t;
|
} display_mode_t;
|
||||||
|
|
||||||
void DrawGUI(epd_model_t *epd, uint32_t timestamp, display_mode_t mode);
|
typedef struct {
|
||||||
|
bool bwr;
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
uint32_t timestamp;
|
||||||
|
int8_t temperature;
|
||||||
|
float voltage;
|
||||||
|
} gui_data_t;
|
||||||
|
|
||||||
|
void DrawGUI(gui_data_t *data, buffer_callback draw, display_mode_t mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
18
Makefile.win32
Normal file
18
Makefile.win32
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
CC = gcc
|
||||||
|
CFLAGS = -Wall -O2 -IGUI -DPAGE_HEIGHT=600
|
||||||
|
LDFLAGS = -lgdi32 -mwindows
|
||||||
|
|
||||||
|
SRCS = GUI/Adafruit_GFX.c GUI/u8g2_font.c GUI/fonts.c GUI/GUI.c GUI/Lunar.c emulator.c
|
||||||
|
OBJS = $(SRCS:.c=.o)
|
||||||
|
TARGET = emulator.exe
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(CC) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) $(TARGET)
|
||||||
21
README.md
21
README.md
@@ -72,6 +72,27 @@
|
|||||||
2. 切换到 `flash_softdevice`,下载蓝牙协议栈,**不要编译直接下载**(只需刷一次)
|
2. 切换到 `flash_softdevice`,下载蓝牙协议栈,**不要编译直接下载**(只需刷一次)
|
||||||
3. 切换到 `nRF51822_xxAA`,先编译再下载
|
3. 切换到 `nRF51822_xxAA`,先编译再下载
|
||||||
|
|
||||||
|
### 模拟器
|
||||||
|
|
||||||
|
本项目提供了一个可在 Windows 下运行界面代码的模拟器,修改了界面代码后无需下载到单片机即可查看效果。
|
||||||
|
|
||||||
|
仿真效果图:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> **提示:** 按 `空格` 可切换日历时钟界面,按 `R` 可切换黑白、三色
|
||||||
|
|
||||||
|
**编译方法:**
|
||||||
|
|
||||||
|
下载并安装 [MSYS2](https://www.msys2.org) 后,打开 `MSYS2 MINGW64` 命令窗口执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pacman -Syu
|
||||||
|
pacman -S make mingw-w64-x86_64-gcc
|
||||||
|
cd <本项目目录>
|
||||||
|
make -f Makefile.win32
|
||||||
|
```
|
||||||
|
|
||||||
## 附录
|
## 附录
|
||||||
|
|
||||||
上位机支持的指令列表(指令和参数全部要使用十六进制):
|
上位机支持的指令列表(指令和参数全部要使用十六进制):
|
||||||
|
|||||||
BIN
docs/images/4.jpg
Normal file
BIN
docs/images/4.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
262
emulator.c
Normal file
262
emulator.c
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
// GUI emulator for Windows
|
||||||
|
// This code is a simple Windows GUI application that emulates the display of an e-paper device.
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "GUI.h"
|
||||||
|
|
||||||
|
#define BITMAP_WIDTH 400
|
||||||
|
#define BITMAP_HEIGHT 300
|
||||||
|
#define WINDOW_WIDTH 400
|
||||||
|
#define WINDOW_HEIGHT 340
|
||||||
|
#define WINDOW_TITLE TEXT("Emurator")
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
HINSTANCE g_hInstance;
|
||||||
|
HWND g_hwnd;
|
||||||
|
display_mode_t g_display_mode = MODE_CALENDAR; // Default to calendar mode
|
||||||
|
BOOL g_bwr_mode = TRUE; // Default to BWR mode
|
||||||
|
|
||||||
|
// Convert bitmap data from e-paper format to Windows DIB format
|
||||||
|
static uint8_t *convertBitmap(uint8_t *bitmap, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
|
||||||
|
int bytesPerRow = ((w + 31) / 32) * 4; // Round up to nearest 4 bytes
|
||||||
|
int totalSize = bytesPerRow * h;
|
||||||
|
|
||||||
|
// Allocate memory for converted bitmap
|
||||||
|
uint8_t *convertedBitmap = (uint8_t*)malloc(totalSize);
|
||||||
|
if (convertedBitmap == NULL) return NULL;
|
||||||
|
|
||||||
|
memset(convertedBitmap, 0, totalSize);
|
||||||
|
|
||||||
|
int ePaperBytesPerRow = (w + 7) / 8; // E-paper buffer stride
|
||||||
|
|
||||||
|
for (int row = 0; row < h; row++) {
|
||||||
|
for (int col = 0; col < w; col++) {
|
||||||
|
// Calculate byte and bit position in e-paper buffer
|
||||||
|
int bytePos = row * ePaperBytesPerRow + col / 8;
|
||||||
|
int bitPos = 7 - (col % 8); // MSB first (typical e-paper format)
|
||||||
|
|
||||||
|
// Check if the bit is set in the e-paper buffer
|
||||||
|
int isSet = (bitmap[bytePos] >> bitPos) & 0x01;
|
||||||
|
|
||||||
|
// Calculate byte and bit position in Windows DIB
|
||||||
|
int dibBytePos = row * bytesPerRow + col / 8;
|
||||||
|
int dibBitPos = 7 - (col % 8); // MSB first for DIB too
|
||||||
|
|
||||||
|
// Set the bit in the Windows DIB if it's set in the e-paper buffer
|
||||||
|
if (isSet) {
|
||||||
|
convertedBitmap[dibBytePos] |= (1 << dibBitPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertedBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation of the buffer_callback function
|
||||||
|
void DrawBitmap(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
|
||||||
|
HDC hdc;
|
||||||
|
RECT clientRect;
|
||||||
|
int scale = 1;
|
||||||
|
|
||||||
|
// Get the device context for immediate drawing
|
||||||
|
hdc = GetDC(g_hwnd);
|
||||||
|
if (!hdc) return;
|
||||||
|
|
||||||
|
// Get client area for positioning
|
||||||
|
GetClientRect(g_hwnd, &clientRect);
|
||||||
|
|
||||||
|
// Calculate position to center the entire bitmap in the window
|
||||||
|
int drawX = (clientRect.right - BITMAP_WIDTH * scale) / 2;
|
||||||
|
int drawY = (clientRect.bottom - BITMAP_HEIGHT * scale) / 2;
|
||||||
|
|
||||||
|
// Create DIB for visible pixels
|
||||||
|
BITMAPINFO bmi;
|
||||||
|
ZeroMemory(&bmi, sizeof(BITMAPINFO));
|
||||||
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
bmi.bmiHeader.biWidth = w;
|
||||||
|
bmi.bmiHeader.biHeight = -h; // Negative for top-down bitmap
|
||||||
|
bmi.bmiHeader.biPlanes = 1;
|
||||||
|
bmi.bmiHeader.biBitCount = 1;
|
||||||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||||||
|
|
||||||
|
uint8_t *convertedBitmap = convertBitmap(black, x, y, w, h);
|
||||||
|
if (convertedBitmap == NULL) {
|
||||||
|
ReleaseDC(g_hwnd, hdc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set colors for black and white display
|
||||||
|
bmi.bmiColors[0].rgbBlue = 0;
|
||||||
|
bmi.bmiColors[0].rgbGreen = 0;
|
||||||
|
bmi.bmiColors[0].rgbRed = 0;
|
||||||
|
bmi.bmiColors[0].rgbReserved = 0;
|
||||||
|
|
||||||
|
bmi.bmiColors[1].rgbBlue = 255;
|
||||||
|
bmi.bmiColors[1].rgbGreen = 255;
|
||||||
|
bmi.bmiColors[1].rgbRed = 255;
|
||||||
|
bmi.bmiColors[1].rgbReserved = 0;
|
||||||
|
|
||||||
|
// Draw the black layer
|
||||||
|
StretchDIBits(hdc,
|
||||||
|
drawX + x * scale, drawY + y * scale, // Destination position
|
||||||
|
w * scale, h * scale, // Destination size
|
||||||
|
0, 0, // Source position
|
||||||
|
w, h, // Source size
|
||||||
|
convertedBitmap, // Converted bitmap bits
|
||||||
|
&bmi, // Bitmap info
|
||||||
|
DIB_RGB_COLORS, // Usage
|
||||||
|
SRCCOPY); // Raster operation code
|
||||||
|
free(convertedBitmap);
|
||||||
|
|
||||||
|
// Handle color layer if present (red in BWR displays)
|
||||||
|
if (color) {
|
||||||
|
// Allocate memory for converted color bitmap
|
||||||
|
uint8_t *convertedColor = convertBitmap(color, x, y, w, h);
|
||||||
|
if (convertedColor) {
|
||||||
|
// Set colors for red overlay
|
||||||
|
bmi.bmiColors[0].rgbBlue = 255;
|
||||||
|
bmi.bmiColors[0].rgbGreen = 255;
|
||||||
|
bmi.bmiColors[0].rgbRed = 0;
|
||||||
|
bmi.bmiColors[0].rgbReserved = 0;
|
||||||
|
|
||||||
|
bmi.bmiColors[1].rgbBlue = 0;
|
||||||
|
bmi.bmiColors[1].rgbGreen = 0;
|
||||||
|
bmi.bmiColors[1].rgbRed = 0;
|
||||||
|
bmi.bmiColors[1].rgbReserved = 0;
|
||||||
|
|
||||||
|
// Draw red overlay
|
||||||
|
StretchDIBits(hdc,
|
||||||
|
drawX + x * scale, drawY + y * scale, // Destination position
|
||||||
|
w * scale, h * scale, // Destination size
|
||||||
|
0, 0, // Source position
|
||||||
|
w, h, // Source size
|
||||||
|
convertedColor, // Converted bitmap bits
|
||||||
|
&bmi, // Bitmap info
|
||||||
|
DIB_RGB_COLORS, // Usage
|
||||||
|
SRCINVERT); // Use XOR operation to blend
|
||||||
|
|
||||||
|
free(convertedColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the device context
|
||||||
|
ReleaseDC(g_hwnd, hdc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window procedure
|
||||||
|
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
|
switch (message) {
|
||||||
|
case WM_CREATE:
|
||||||
|
// Set a timer to update the display periodically (every second)
|
||||||
|
SetTimer(hwnd, 1, 1000, NULL);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_TIMER:
|
||||||
|
// Force a redraw of the window without erasing the background
|
||||||
|
InvalidateRect(hwnd, NULL, FALSE);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_PAINT: {
|
||||||
|
PAINTSTRUCT ps;
|
||||||
|
HDC hdc = BeginPaint(hwnd, &ps);
|
||||||
|
|
||||||
|
// Get client rect for calculations
|
||||||
|
RECT clientRect;
|
||||||
|
GetClientRect(hwnd, &clientRect);
|
||||||
|
|
||||||
|
// Clear the entire client area with a solid color
|
||||||
|
HBRUSH bgBrush = CreateSolidBrush(RGB(240, 240, 240));
|
||||||
|
FillRect(hdc, &clientRect, bgBrush);
|
||||||
|
DeleteObject(bgBrush);
|
||||||
|
|
||||||
|
// Get current timestamp
|
||||||
|
gui_data_t data = {
|
||||||
|
.bwr = g_bwr_mode,
|
||||||
|
.width = BITMAP_WIDTH,
|
||||||
|
.height = BITMAP_HEIGHT,
|
||||||
|
.timestamp = time(NULL) + 8*3600,
|
||||||
|
.temperature = 25,
|
||||||
|
.voltage = 3.2f,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Call DrawGUI to render the interface, passing the BWR mode
|
||||||
|
DrawGUI(&data, DrawBitmap, g_display_mode);
|
||||||
|
|
||||||
|
EndPaint(hwnd, &ps);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
// Toggle display mode with spacebar
|
||||||
|
if (wParam == VK_SPACE) {
|
||||||
|
if (g_display_mode == MODE_CLOCK)
|
||||||
|
g_display_mode = MODE_CALENDAR;
|
||||||
|
else
|
||||||
|
g_display_mode = MODE_CLOCK;
|
||||||
|
|
||||||
|
InvalidateRect(hwnd, NULL, TRUE);
|
||||||
|
}
|
||||||
|
// Toggle BWR mode with R key
|
||||||
|
else if (wParam == 'R') {
|
||||||
|
g_bwr_mode = !g_bwr_mode;
|
||||||
|
InvalidateRect(hwnd, NULL, TRUE);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_DESTROY:
|
||||||
|
KillTimer(hwnd, 1);
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main entry point
|
||||||
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||||
|
g_hInstance = hInstance;
|
||||||
|
|
||||||
|
// Register window class
|
||||||
|
WNDCLASSA wc = {0}; // Using WNDCLASSA for ANSI version
|
||||||
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||||
|
wc.lpfnWndProc = WndProc;
|
||||||
|
wc.hInstance = hInstance;
|
||||||
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
||||||
|
wc.lpszClassName = "BitmapDemo"; // No L prefix - using ANSI strings
|
||||||
|
|
||||||
|
if (!RegisterClassA(&wc)) {
|
||||||
|
MessageBoxA(NULL, "Window Registration Failed!", "Error", MB_ICONEXCLAMATION | MB_OK);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the window - explicit use of CreateWindowA for ANSI version
|
||||||
|
g_hwnd = CreateWindowA(
|
||||||
|
"BitmapDemo",
|
||||||
|
"Emurator (Press Space/R Key)", // Using simple title
|
||||||
|
WS_OVERLAPPEDWINDOW,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
WINDOW_WIDTH, WINDOW_HEIGHT,
|
||||||
|
NULL, NULL, hInstance, NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!g_hwnd) {
|
||||||
|
MessageBoxA(NULL, "Window Creation Failed!", "Error", MB_ICONEXCLAMATION | MB_OK);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show window
|
||||||
|
ShowWindow(g_hwnd, nCmdShow);
|
||||||
|
UpdateWindow(g_hwnd);
|
||||||
|
|
||||||
|
// Main message loop
|
||||||
|
MSG msg;
|
||||||
|
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)msg.wParam;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user