Функции *_at принимают абсолютный MCU-адрес; смещение в буфере
вычисляется автоматически:
buffer_offset = addr - region.start_address.
-- Flash начинается с 0x4000. Чтение 4 байт по адресу 0xF650:
local bytes = mp.memory.read_at("Flash", 0xF650, 4)
-- внутри читает смещение в буфере: 0xF650 - 0x4000 = 0xB650
Навигация по регионам
| Функция | Возврат | Описание |
|---|
get_regions() | table | Массив имён регионов |
current_region() | string | Имя активного региона |
region_count() | int | Количество регионов |
select_region(idx) | void | Переключить регион по индексу (с 0) |
select_region_by_name(n) | bool | Переключить регион по имени |
get_region_info([r]) | table | {index, name, size, start_address, end_address, cell_size} — r это имя, индекс или опущен (активный) |
region_size(r) | int | Размер региона в байтах |
Редактируемость
Вкладки по умолчанию read-only, как в GUI. Записи молча возвращают
false, пока не включить writability.
| Функция | Возврат | Описание |
|---|
set_writable(r, b) | ok, err | r — имя или индекс; b — bool. Голый set_writable(b) (один bool) переключает все табы. set_writable(0) (число) → (false, "...") |
set_writable_all(b) | ok, err | Применить ко всем регионам |
is_writable([r]) | bool | r — имя, индекс или опущен (активный регион) |
Чтение — по смещению
| Функция | Возврат | Описание |
|---|
read_byte(r, off) | int | Один байт (-1 если вне диапазона) |
read_range(r, start, len) | table | Массив байт |
read_bytes(r, off, n) | table | Массив байт (alias-class с read_range) |
read_hex(r, off, n) | string | Hex-строка, например "deadbeef" |
read_string(r, off, maxLen) | string | Сырая строка (может содержать непечатное) |
read_string_until_null(r, off, maxLen?) | string | До первого NUL (по умолчанию макс 256) |
get_region_data(r) | table | Весь регион как массив байт |
get_all_data() | table | Все регионы подряд как массив байт |
Чтение — по адресу
| Функция | Возврат | Описание |
|---|
read_at(r, addr, n) | table | Массив байт начиная с MCU-адреса |
read_byte_at(r, addr) | int | Один байт по MCU-адресу |
read_string_at(r, addr, maxLen) | string | Сырая строка по MCU-адресу |
read_string_until_null_at(r, addr, maxLen?) | string | До первого NUL по абсолютному адресу (макс 256) |
Запись — по смещению
| Функция | Возврат | Описание |
|---|
write_byte(r, off, v) | bool | Один байт |
write_range(r, off, bytes) | bool | Массив байт |
write_hex(r, off, hexStr) | bool | Байты из hex-строки |
write_string(r, off, text) | bool | Сырая строка |
fill(r, off, len, v) | bool | Заливка константой |
fill_pattern(r, off, len, pattern) | bool | Заливка повторяющимся паттерном байт |
Запись — по адресу
| Функция | Возврат | Описани е |
|---|
write_at(r, addr, bytes) | bool | Массив байт по MCU-адресу |
write_byte_at(r, addr, v) | bool | Один байт по MCU-адресу |
write_string_at(r, addr, text) | bool | Сырая строка по MCU-адресу |
Поиск
| Функция | Возврат | Описание |
|---|
find(r, hex, startOff?) | int | Смещение первого совпадения или -1 |
find_prev(r, hex, startOff?) | int | Последнее совпадение до start, или -1 |
find_all(r, hex) / find_all(r, byte_table) | table | Массив смещений в регионе. Для ASCII используйте byte-table или find_string |
find_string(r, text, startOff?) | int | Первое ASCII-совпадение или -1 |
search_all(hex) / search_all(region, hex) | table | {region, offset, address, offset_hex, address_hex} на каждое совпадение. Без region — по всем регионам |
search_string_all(text) / search_string_all(region, text) | table | То же + context_hex (совпавшие байты + 16 после) |
search_patterns(patterns) | table | Батч: {label, hits[], count} |
Выделение и курсор
| Функция | Возврат | Описание |
|---|
set_selection(r, off, len) | void | Выделить диапазон |
get_selection(r) | table | {start, end, length, hex} или пустая |
go_to(r, off) | ok, err | Переместить курсор на смещение |
cursor_offset(r) | int | Текущее смещение курсора |
Undo / redo
| Функция | Возврат | Описание |
|---|
undo(r) | void | Откатить последнее |
redo(r) | void | Повторить |
can_undo(r) | bool | — |
can_redo(r) | bool | — |
Закладки
| Функция | Возврат | Описание |
|---|
add_bookmark(r, off, comment) / add_bookmark(off, comment) | ok, err | Добавить закладку |
get_bookmarks(r) / get_bookmarks() / list_bookmarks(...) | table | Массив {offset, comment} |
clear_bookmarks(r) | void | Удалить все |
Конвертация адресов
| Функция | Возврат | Описание |
|---|
addr_to_offset(r, addr) | int | MCU-адрес → смещение в буфере (-1 если ниже базы) |
offset_to_addr(r, off) | int | Смещение в буфере → MCU-адрес |
Буфер и экспорт
| Функция | Возврат | Описание |
|---|
clear() | void | Очистить все буферы (через backend) |
load_file() / show_load_dialog() | void | Открыть диалог импорта |
load_file(path) | ok, err | Парсит файл, запол няет регионы по совпавшим адресам |
save_file() / show_save_dialog() | void | Открыть диалог экспорта |
save_file(path) | ok, err | Записать все регионы в <path> (формат по расширению) |
export_region(r, path[, off, len]) | string | Ошибка или пусто. Опц. off, len — слайс в байтах буфера; адрес в файле = start_address + off |
export_all(path) | string | Экспорт всех регионов в один файл |
compare(r1, r2) | table | {diffs[], diff_count, size1, size2, equal} |
Имена регионов и cell_size — типичные ловушки
Три момента, на которых спотыкается каждый новый автор скрипта:
1. Имена регионов — не везде "Flash"
Каждый бэкенд использует свои — P_Flash, D_Flash, RAM_P (DSC),
Code Flash, EEPROM, User Boot и т.д. Не хардкодьте,
перечислите сначала:
for i, name in ipairs(mp.memory.get_regions()) do
mp.log.info(i .. ": " .. name)
end
При ошибочном имени read_byte / go_to / cursor_offset молча
возвращают 0 / false / -1. Бэкенд логирует [QT-WARN]
со списком актуальных имён — смотрите лог, если что-то «всегда
возвращает 0».
2. Содержимое буфера сразу после set_target — НЕ чип
Большинство бэкендов префиллят регион байтами 0xFF на полный
размер, поэтому region_size может уже вернуть реальный размер
flash, а read_byte возвращает 0xFF — это не содержимое
чипа, это dummy «erased flash» заглушка. Всегда вызывайте
mp.backend.read() (или mp.file.load(path)) до выводов
о содержимом чипа.
3. Word-addressed таргеты — DSC, dsPIC и подобные
Freescale / NXP DSC (MC56F8xxx) word-addressed: один адрес
устройства указывает на 16-битную ячейку, но в буфере лежат байты,
поэтому region.size — в 2 раза больше числа адресуемых слов,
а cell_size = 2.
Проверяйте cell_size и пересчитывайте на границе адрес ↔
смещение в буфере:
local info = mp.memory.get_region_info() -- например, P_Flash на MC56F8006
-- info.start_address = 0x800, size = 12288 (байт), cell_size = 2
-- → 6144 word-адресов от 0x800 до 0x37FF
-- byte_offset (Lua API) = (адрес_устройства - start_address) * cell_size
local addr = 0x900
local byte_offset = (addr - info.start_address) * info.cell_size -- 0x200
local lo = mp.memory.read_byte(info.name, byte_offset)
local hi = mp.memory.read_byte(info.name, byte_offset + 1)
local word = lo | (hi << 8)
_at-семейство (read_at, read_byte_at, write_at,
write_byte_at, addr_to_offset, offset_to_addr) не умножает
на cell_size — они трактуют address - start_address как байтовый
offset в буфер. Для cell_size == 1 это совпадает; для DSC вы
должны сами умножать на cell_size, либо работать сразу в байтовых
offset через read_range / read_byte.
mp.memory.go_to(region, off) и cursor_offset(region) работают
в байтах буфера, а не в word-адресах устройства — умножайте
свой адрес на cell_size, если он пришёл из datasheet или HEX-файла.