# Пример простого плагина для WC ## Минимальный плагин "Hello World" Этот пример показывает базовую структуру плагина для Wild Commander. ```asm ;--------------------------------------- ; Hello World Plugin ; Простейший пример плагина для WC ;--------------------------------------- ORG #6000 ; Константы WC API WLD EQU #6006 ; Точка вызова API ABT EQU #6004 ; Флаг ESC ENT EQU #6005 ; Флаг ENTER ;--------------------------------------- ; ЗАГОЛОВОК ПЛАГИНА (512 байт) ;--------------------------------------- ; +0: Резерв (16 байт) DS 16 ; +16: Идентификатор (16 байт) DB "WildCommanderMDL" ; +32: Версия формата DB #10 ; +33: Резерв DB 0 ; +34: Количество страниц DB 1 ; Плагин занимает 1 страницу ; +35: Стартовая страница DB 0 ; Запускаться будет со страницы 0 ; +36: Блоки данных (6 x 2 байта) DB 0,1 ; Блок 0: код, 1x512 байт DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 ; +48: Резерв (15 байт) DS 15 ; +63: Флаги расширений DB 0 ; Стандартный режим ; +64: Блок расширений (32 x 3 байта) DS 32*3 ; Не используем расширения ; +160: Конец блока расширений DB 0 ; +161: Максимальный размер файла (4 байта) DW #FFFF,#FFFF ; Без ограничений ; +165: Имя плагина (32 байта) DB "Hello World Plugin " ; +197: Тип условий вызова DB #03 ; Из меню (F10) ; +198: Текст для F2/F4 (6 байт) DS 6 ; +204: Текст для меню вьювера (24 байта) DS 24 ; +228: Резерв (32 байта) DS 32 ; +260: Параметры INI (252 байта) DB 0 ; Нет параметров DS 251 ;--------------------------------------- ; КОД ПЛАГИНА ;--------------------------------------- ORG #8000,#6200 ;--------------------------------------- ; Точка входа плагина ;--------------------------------------- PLUGIN: ; Сохранить входные параметры LD (SAVE_IX),IX LD (SAVE_HL),HL LD (SAVE_DE),DE LD (SAVE_BC),BC LD (SAVE_A),A ; Восстановить текстовый режим CALL GEDPL ; Показать окно LD IX,WINDOW CALL PRWOW ; Вывести текст LD HL,TEXT LD DE,#0102 ; Y=1, X=2 LD BC,12 ; Длина CALL PRSRW ; Применить цвет EXA LD A,%00001111 ; Синий на белом CALL PRIAT EXA ; Главный цикл MAIN_LOOP: EI HALT ; Ждем прерывание ; Проверка ESC CALL ESC_KEY JR Z,MAIN_LOOP ; Выход LD IX,WINDOW CALL RRESB ; Стереть окно XOR A ; A=0: просто выход RET ;--------------------------------------- ; WC API функции ;--------------------------------------- PRWOW: ; Вывод окна LD A,1 JP WLD RRESB: ; Стирание окна LD A,2 JP WLD PRSRW: ; Печать строки LD A,3 JP WLD PRIAT: ; Установка цвета EXA LD A,4 JP WLD ESC_KEY: ; Проверка ESC LD A,#17 JP WLD GEDPL: ; Восстановление TXT режима LD A,#0F JP WLD ;--------------------------------------- ; Данные ;--------------------------------------- ; Структура окна WINDOW: DB 0 ; Флаги DB 0 ; Маска курсора DB 255 ; X (центр) DB 255 ; Y (центр) DB 30 ; Ширина DB 5 ; Высота DB %01111111 ; Цвет (белый на синем) DB 0 ; Резерв DW #0000 ; Буфер DB 0,0 ; Разделители ; Текст TEXT: DB "Hello World!" ; Сохраненные регистры SAVE_A: DB 0 SAVE_BC: DW 0 SAVE_DE: DW 0 SAVE_HL: DW 0 SAVE_IX: DW 0 END ``` ## Компиляция Используйте sjasm для компиляции: ```batch sjasm hello.asm hello.wmf ``` ## Пояснения к коду ### Структура 1. **Заголовок (#6000-#61FF)** - 512 байт метаданных 2. **Код (#8000+)** - исполняемый код плагина ### Ключевые моменты 1. **GEDPL обязателен!** Вызывайте его в начале, чтобы восстановить текстовый режим. 2. **Структура окна** должна быть в памяти плагина (#8000-#BFFF). 3. **Главный цикл** должен включать: - `EI` - разрешить прерывания - `HALT` - ждать прерывание (экономит энергию) - Проверку клавиш 4. **Выход** через `RET` с кодом в A. ## Пример с файлом ```asm ;--------------------------------------- ; Text Viewer Plugin - просмотр текстовых файлов ;--------------------------------------- ORG #6000 WLD EQU #6006 ; ... Заголовок плагина ... ; +64: Расширения DB "TXT" ; .txt файлы DB "DOC" ; .doc файлы DS 30*3 ; +197: Тип вызова DB #00 ; По расширению ORG #8000,#6200 ;--------------------------------------- ; Точка входа ;--------------------------------------- PLUGIN: ; Проверить тип вызова CP #00 ; По расширению? JR Z,VIEW_FILE ; Другой тип вызова - не наш файл LD A,1 ; Файл не опознан RET VIEW_FILE: ; Сохранить параметры LD (FILESIZE),HL LD (FILESIZE+2),DE LD (FILENAME),BC LD (PANEL_IX),IX ; Восстановить TXT режим CALL GEDPL ; Загрузить начало файла LD HL,BUFFER LD B,16 ; 16 блоков = 8KB CALL LOAD512 ; Показать окно LD IX,WINDOW CALL PRWOW ; Вывести текст LD HL,BUFFER LD DE,#0101 LD BC,1000 CALL PRSRW ; Цикл просмотра VIEW_LOOP: EI HALT CALL ESC_KEY JR Z,VIEW_LOOP ; Выход LD IX,WINDOW CALL RRESB XOR A RET ;--------------------------------------- ; WC API ;--------------------------------------- LOAD512: LD A,#30 JP WLD PRWOW: LD A,1 JP WLD RRESB: LD A,2 JP WLD PRSRW: LD A,3 JP WLD ESC_KEY: LD A,#17 JP WLD GEDPL: LD A,#0F JP WLD ;--------------------------------------- ; Данные ;--------------------------------------- WINDOW: DB 0 DB 0 DB 0 ; X=0 DB 0 ; Y=0 DB 80 ; На весь экран DB 25 DB %01111111 DB 0 DW #0000 DB 0,0 BUFFER: DS 8192 ; Буфер для файла FILENAME: DW 0 FILESIZE: DS 4 PANEL_IX: DW 0 END ``` ## Следующий шаг Изучите примеры в каталоге PlugRef/: - **wild_player/** - полноценный музыкальный плеер - **gsplayer/** - плеер для GS - **txt_editor/** - редактор текста --- ## Минимальный плагин на SDCC C > Компилятор: SDCC 4.x, ключи `--opt-code-size -mz80 --sdcccall 1` > Источник соглашений: `src_sdcc/inc/wc_api.h` ```c /* * hello_plugin.c — минимальный WC-плагин на SDCC C * * Сборка: * sdcc --opt-code-size -mz80 --sdcccall 1 --code-loc 0x8000 \ * --data-loc 0xB800 -I inc hello_plugin.c wc_api.s crt0.s * makebin -s 16384 hello_plugin.ihx hello_plugin.bin * pack hello_plugin.bin HELLO.WMF # добавить заголовок WMF */ #include "inc/wc_api.h" #include "inc/types.h" /* ───────────────────────────────────────────────── * DATA: размещается в #B800+ (--data-loc 0xB800) * ──────────────────────────────────────────────── */ /* Окно в секции DATA (адрес в #8000–#BFFF — обязательно!) */ static wc_window_t g_win; /* Буфер вывода */ static char g_buf[64]; /* * wc_exit_code — специальная переменная: WC читает A при * выходе из main(). Значения: 0=ESC, 2=след. файл, 3=reload dir. */ uint8_t wc_exit_code; /* ───────────────────────────────────────────────── * CODE: размещается в #8000+ (--code-loc 0x8000) * ──────────────────────────────────────────────── */ int main(void) { /* 1. Восстановить дисплей WC (TXT-режим, панели) * ⚠ Затирает #1000–#1447 в окне 0 */ wc_gedpl(); /* 2. Настроить окно */ g_win.type = WC_WIN_SINGLE; /* однолинейная рамка */ g_win.cur_mask = 0x07; g_win.x = 255; /* 255 = по центру */ g_win.y = 255; g_win.width = 44; g_win.height = 6; g_win.color = WC_COLOR(WC_BLACK, WC_BRIGHT_WHITE); g_win.buf_addr = 0x0000; /* 0 = автосохранение фона в RESB */ /* 3. Нарисовать окно */ wc_prwow(&g_win); /* 4. Вывести текст (разметка WC: 0x0E = центрирование) */ wc_txtpr(&g_win, "\x0eHello from C plugin!", 1, 1); wc_txtpr(&g_win, "\x0e\x03Press ESC to exit", 3, 1); /* 5. Главный цикл */ while (1) { if (wc_key_esc()) break; if (wc_key_enter()) break; /* пример: цикл ожидания клавиши без блокировки */ /* uint8_t k = wc_kbscn(WC_KBSCN_NORMAL); */ } /* 6. Убрать окно и восстановить дисплей */ wc_rresb(&g_win); wc_gedpl(); /* 7. Код выхода */ wc_exit_code = 0; /* 0 = нормальный выход */ return 0; } ``` ### Полезные паттерны **Загрузка файла в мегабуфер:** ```c void load_file_to_megabuf(void) { uint8_t page = 0; uint8_t rc; wc_stream(WC_STREAM_ROOT); // открыть файловый поток // wc_fentry() уже вызван WC перед стартом плагина do { /* ⚠ После любого wc_* Win3 сбрасывается — переключаем снова */ wc_mngcvpl(page); rc = wc_load512(0xC000, 32); // читать 16 КБ page++; } while (rc == 0 && page < 64); /* rc == WC_EOF (0x0F) = конец файла, rc != 0 && != 0x0F = ошибка */ } ``` **Установка собственного ISR:** ```c extern void my_isr(void); // ISR написан на ASM в asm/isr.s void setup_isr(void) { wc_int_pl(WC_INT_PLUGIN); // режим плагина wc_int_pl_handler((uint16_t)my_isr); // задать адрес /* Теперь my_isr() вызывается ~1367 раз/сек */ } void restore_isr(void) { wc_int_pl(WC_INT_DISABLE_ALL); // вернуть управление WC } ``` **Переключение CPU на 14 МГц:** ```c wc_turbopl(WC_TURBO_CPU, 0x02); // 14 МГц // ...работа... wc_turbopl(WC_TURBO_RESTORE, 0); // восстановить ```