13 KiB
13 KiB
Пример простого плагина для WC
Минимальный плагин "Hello World"
Этот пример показывает базовую структуру плагина для Wild Commander.
;---------------------------------------
; 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 для компиляции:
sjasm hello.asm hello.wmf
Пояснения к коду
Структура
- Заголовок (#6000-#61FF) - 512 байт метаданных
- Код (#8000+) - исполняемый код плагина
Ключевые моменты
-
GEDPL обязателен! Вызывайте его в начале, чтобы восстановить текстовый режим.
-
Структура окна должна быть в памяти плагина (#8000-#BFFF).
-
Главный цикл должен включать:
EI- разрешить прерыванияHALT- ждать прерывание (экономит энергию)- Проверку клавиш
-
Выход через
RETс кодом в A.
Пример с файлом
;---------------------------------------
; 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
/*
* 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;
}
Полезные паттерны
Загрузка файла в мегабуфер:
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:
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 МГц:
wc_turbopl(WC_TURBO_CPU, 0x02); // 14 МГц
// ...работа...
wc_turbopl(WC_TURBO_RESTORE, 0); // восстановить