Skip to main content

mowatch-dev

Development guide for MoWatch e-ink smartwatch apps. Use when developing watch faces, apps, or processing images for MoWatch. Includes complete API reference, bitmap format, Docker build process, and image processing for 1-bit e-ink display.

Ir para a instalação

Informações da origem

Repositório
yetone/agent-skill-mowatch-dev
Última atividade na origem
3 de fevereiro de 2026 às 08:22
Idioma detectado do SKILL.md
inglês
Estrelas
7
Forks
0

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
mowatch-dev
description
Development guide for MoWatch e-ink smartwatch apps. Use when developing watch faces, apps, or processing images for MoWatch. Includes complete API reference, bitmap format, Docker build process, and image processing for 1-bit e-ink display.
license
MIT
# MoWatch App Development Skill Use this skill when developing watch faces or apps for MoWatch e-ink smartwatch. ## SDK Files Location **IMPORTANT**: SDK source files are located in this skill's directory. Copy them to create a new project: ``` ~/.claude/skills/mowatch-dev/ ├── sdk/ │ ├── include/header.h # SDK header - copy to include/ │ └── libs/ │ ├── init_datas.c # API wrappers - copy to libs/ │ └── syscall_gcc.txt # Syscall addresses - copy to libs/ └── templates/ ├── Makefile # Build config - copy to gcc/ ├── app.ld # Linker script - copy to gcc/ └── createmwa.py # Package creator - copy to gcc/ ``` To create a new project, read and copy these files using the Read tool. ## Hardware Specifications - **Display**: 200x200 pixel monochrome e-ink - **MCU**: ARM Cortex-M3 - **Colors**: Black and white only (1-bit) - **Update**: Partial refresh supported, full refresh every 5 minutes recommended ## Memory Constraints (IMPORTANT!) ```c FLASH (rx) : ORIGIN = 0x10050000, LENGTH = 40K // Code + constants RAM (xrw) : ORIGIN = 0x11001000, LENGTH = 4K // Variables only! ``` **Only 4K RAM available!** Keep global variables minimal. Use `const` for bitmap data. ## Constants ```c #define SCREEN_WIDTH 200 #define SCREEN_HEIGHT 200 #define BLACK 0 #define WHITE 0xFF #define GREY 0x80 #define MODE_EMPTY 0 // Rectangle outline #define MODE_FILL 1 // Filled rectangle // File access flags #define FA_READ 0x01 #define FA_WRITE 0x02 #define FA_OPEN_EXISTING 0x00 #define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_APPEND 0x30 ``` ## Enums and Data Structures ### Update Types ```c typedef enum UPDAT_TYPE { FULL_UPDATE, // Full screen refresh (prevents ghosting) PART_UPDATE, // Partial refresh (faster but may ghost) NONE_UPDATE, // No screen update } UpdateType; ``` ### Button Types ```c typedef enum MBUTTON_TYPE { KEY_NULL, KEY_CENTER, // Center button press KEY_UP, // Up button press KEY_DOWN, // Down button press KEY_CENTER_UP, // Center then Up KEY_UP_CENTER, // Up then Center KEY_CENTER_DOWN, // Center then Down KEY_DOWN_CENTER, // Down then Center KEY_UP_DOWN, // Up then Down KEY_DOWN_UP, // Down then Up KEY_BACK, // Back/exit } ButtonType; ``` ### Rotation ```c typedef enum ROTATE { ROTATE_0, ROTATE_90, ROTATE_180, ROTATE_270, } Rotate; ``` ### Bluetooth State ```c typedef enum BLUESTTE { DISCONNECTED, CONNECTING, CONNECTED, } BlueState; ``` ### Weather Data ```c typedef enum WEATHERDAY { TOTDAY, // Today TOMORROW, AFTERTOMOROW, // Day after tomorrow DAY_COUNT, } WeatherDay; typedef struct TODAYDATA { uint16_t moonicon; // Moon phase icon index uint16_t pressure; // Air pressure uint16_t humidity; // Humidity percentage uint8_t sunraise[6]; // Sunrise time string "HH:MM" uint8_t sunset[6]; // Sunset time string "HH:MM" uint8_t lunar[16]; // Lunar date string } TodayData; typedef struct WEATHER { uint8_t date; // Day of month char day_temp; // Daytime temperature char night_temp; // Nighttime temperature uint16_t day_icon; // Daytime weather icon uint16_t night_icon; // Nighttime weather icon } Weather; ``` ## Bitmap Format MoWatch uses **horizontal 8-point left-high-bit encoding**: ```c // For a 120px wide image: int16_t byteWidth = (120 + 7) / 8; // = 15 bytes per row // To check if pixel (x, y) is black: if (bitmap[y * byteWidth + x / 8] & (128 >> (x & 7))) { // pixel is black } ``` ## Project Structure ``` app_projects/ ├── include/ │ └── header.h # SDK header (from skill sdk/) ├── libs/ │ ├── init_datas.c # SDK init (from skill sdk/) │ ├── tiny-json.c # JSON library (optional) │ └── syscall_gcc.txt # Syscall definitions (from skill sdk/) └── app_yourapp/ ├── code/ │ ├── app_main.c # Your main code │ └── graphics.h # Your bitmap data (optional) └── gcc/ ├── Makefile # From skill templates/ ├── app.ld # From skill templates/ └── createmwa.py # From skill templates/ ``` ## Complete API Reference ### Drawing Functions ```c // Clear entire screen void eink_clear(uint16_t color); // Draw single pixel void eink_drawpixel(uint16_t x, uint16_t y, uint16_t color); // Draw line void eink_drawline(uint16_t start_x, uint16_t start_y, uint16_t end_x, uint16_t end_y, uint16_t color); // Draw dashed line void eink_drawdashedline(uint16_t start_x, uint16_t start_y, uint16_t end_x, uint16_t end_y, uint16_t color); // Draw rectangle (MODE_EMPTY=outline, MODE_FILL=filled) void eink_drawrect(uint16_t start_x, uint16_t start_y, uint16_t end_x, uint16_t end_y, uint16_t color, uint8_t fill_mode); // Draw circle void eink_drawcircle(int x_center, int y_center, int radius, int color, int fill_mode); // Draw bitmap - THE MOST IMPORTANT FUNCTION! // x, y: top-left position // w, h: width and height in pixels // data[]: bitmap array (horizontal 8-point left-high-bit) // color: drawing color (BLACK or WHITE) // transparent: 0=draw both colors, 1=only draw foreground void eink_draw_bmp(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t data[], uint16_t color, uint8_t transparent); // Draw ASCII string // Returns: width of drawn string uint16_t eink_drawstr(uint16_t x, uint16_t y, const unsigned char *chr, uint16_t size, uint16_t color); // Draw Chinese string (UTF-8) uint16_t eink_drawchstr(uint16_t x, uint16_t y, const unsigned char *chr, uint16_t color); // Draw string within rectangle bounds uint16_t eink_draw_rectstr(const unsigned char *chr, uint16_t start_x, uint16_t start_y, uint16_t end_x, uint16_t end_y, uint16_t color); // Set screen rotation void eink_set_rotate(Rotate rotate); // Get weather icon bitmap (32x32) into buffer void get_weather_icon(uint16_t iconidx, uint8_t *buffer); ``` ### Time Functions ```c int RTC_getYear(void); // Full year (e.g., 2024) int RTC_getMon(void); // Month 1-12 int RTC_getDay(void); // Day 1-31 int RTC_getHour(void); // Hour 0-23 int RTC_getMin(void); // Minute 0-59 int RTC_getSec(void); // Second 0-59 int RTC_getWeek(void); // Day of week (0=Sunday) int RTC_getTimeStamp(void); // Unix timestamp ``` ### System Functions ```c // Get battery percentage (0-100) uint8_t watch_app_battpercent(void); // Exit app, return to main menu void watch_app_exit(void); // Set update interval for onUpdate() callback (in milliseconds) void set_update_interval(uint32_t interval); // Get current update interval uint32_t get_update_interval(void); // Log message (for debugging) void watch_app_log(char* log); // Get Bluetooth connection state BlueState watch_app_bluestate(void); // Check if weather data is available uint8_t watch_app_isweather_ok(void); // Get today's data (sunrise, sunset, lunar, etc.) TodayData watch_app_getToday(void); // Get weather for specified day Weather watch_app_getweather(WeatherDay day); // HTTP request (async, result via callback) void watch_app_http_req(const char* url, void(req_callback)(char*)); ``` ### File Operations ```c // Read file // Returns: bytes read uint32_t watch_app_read_file(const uint8_t* file_name, uint8_t* buffer, uint32_t len, uint32_t seekofs); // Write file // fa_mode: FA_CREATE_ALWAYS, FA_OPEN_APPEND, etc. uint32_t watch_app_write_file(const uint8_t* file_name, uint8_t* buffer, uint32_t len, uint32_t seekofs, uint8_t fa_mode); // Delete file uint8_t watch_app_delete_file(const uint8_t* file_name); // Create directory uint8_t watch_app_mkdir(const uint8_t* dir); ``` ### Memory Functions ```c // Allocate memory (use sparingly - only 4K RAM!) void *m_malloc(uint32_t size); // Free memory void m_free(void *ptr); ``` ### Utility Functions ```c // Format string (like sprintf) void co_sprintf(char *out, const char *format, ...); // Get UTF-8 string length uint16_t utf_len(const unsigned char *chr); // Random number int rand(void); void srand(unsigned int seed); ``` ### Dialog Functions ```c // Show message dialog with OK/Cancel // submit callback receives: 1=OK, 0=Cancel void create_msg_dialog(const uint8_t* title, const uint8_t* msg, void (*submit)(uint8_t ok)); // Show menu dialog void create_menu_dialog(const char* title, const char** menu_item_names, const uint8_t count, void (*submit)(uint8_t confirm)); // Show number picker dialog void create_picker_dialog(uint8_t num, const uint8_t* nums, const uint8_t count, void (*submit)(uint8_t data)); ``` ## App Entry Points ```c #include "header.h" // Called when screen needs to be drawn void onDraw(void) { eink_clear(WHITE); // Draw your UI here } // Called when button is pressed // Return update type to trigger screen refresh UpdateType onKey(ButtonType key) { switch(key) { case KEY_BACK: watch_app_exit(); break; case KEY_UP: // Handle up button break; case KEY_DOWN: // Handle down button break; } return PART_UPDATE; // or NONE_UPDATE, FULL_UPDATE } // Called periodically based on set_update_interval() UpdateType onUpdate(int delta) { static uint8_t lastmin = 61; if (lastmin != RTC_getMin()) { lastmin = RTC_getMin(); return PART_UPDATE; // Refresh screen when minute changes } return NONE_UPDATE; } // App initialization - REQUIRED void app_init(intptr_t *draw_ptr_t, intptr_t *onkey_ptr_t, intptr_t *update_ptr_t, intptr_t* func_arr) { __initialize_datas(func_arr); *draw_ptr_t = (intptr_t)onDraw; *onkey_ptr_t = (intptr_t)onKey; *update_ptr_t = (intptr_t)onUpdate; // Initialize your variables here set_update_interval(1000); // Check every 1 second } ``` ## Complete Minimal Example ```c // app_main.c - Simple digital clock using eink_drawstr #include "header.h" void onDraw(void) { eink_clear(WHITE); char buf[32]; // Draw time (large, centered) co_sprintf(buf, "%02d:%02d", RTC_getHour(), RTC_getMin()); eink_drawstr(50, 80, (unsigned char*)buf, 32, BLACK); // Draw date co_sprintf(buf, "%04d-%02d-%02d", RTC_getYear(), RTC_getMon(), RTC_getDay()); eink_drawstr(40, 130, (unsigned char*)buf, 16, BLACK); // Draw battery co_sprintf(buf, "BAT:%d%%", watch_app_battpercent()); eink_drawstr(140, 5, (unsigned char*)buf, 12, BLACK); } UpdateType onKey(ButtonType key) { if (key == KEY_BACK || key == KEY_CENTER) { watch_app_exit(); } return NONE_UPDATE; } UpdateType onUpdate(int delta) { static uint8_t lastmin = 61; if (lastmin != RTC_getMin()) { lastmin = RTC_getMin(); if (RTC_getMin() % 5 == 0) { return FULL_UPDATE; } return PART_UPDATE; } return NONE_UPDATE; } void app_init(intptr_t *draw_ptr_t, intptr_t *onkey_ptr_t, intptr_t *update_ptr_t, intptr_t* func_arr) { __initialize_datas(func_arr); *draw_ptr_t = (intptr_t)onDraw; *onkey_ptr_t = (intptr_t)onKey; *update_ptr_t = (intptr_t)onUpdate; set_update_interval(1000); } ``` ## Building with Docker
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub