简易데이터库(定制固件专属)是一个轻量级、无文件系统的嵌入式데이터库:在 Flash 里划一块连续区域,按固定길이记录存结构化데이터(매개변수설정、事件로그、运行记录),掉电不丢,支持运行时按需初始化。데이터记录控件用「自定义」데이터源모드对接,实现增删改查全流程。
1. ⚠️ Flash 주소规划(不看会变砖)
简易데이터库直接操作 Flash,没有文件系统隔离机制,flashaddr 시작주소必须严格避开四类高风险区域:
- 엔지니어링자료存储区
- 자료采样块存储区
- 操作记录块存储区
- OTA 업그레이드备份区域
总占用空间 = 데이터RowSize × maxCount,规划주소时把这段空间算进去,别和别的功能打架。
2. API 总表
| 函数 | 매개변수 | 설명 |
|---|---|---|
easydb_열기(flashaddr, createIfNotExist, 데이터RowSize, maxCount) | flashaddr Flash 시작주소;createIfNotExist 0=仅열기/1=不存在则创建;데이터RowSize ≥1;maxCount 最大条数 | 열기或创建데이터库,返回句柄(非 0 成功,0 失败) |
easydb_close(db) | 句柄 | 닫기데이터库,释放자료 |
easydb_get_count(db) | 句柄 | 当前有效记录数 |
easydb_get(db, idx) | idx 从 0 开始 | 读指定索引记录,成功返回문자串,失败 nil |
easydb_add(db, 데이터set) | 문자串데이터 | 末尾追加一条记录 |
easydb_update(db, idx, 데이터set) | idx + 新콘텐츠 | 更新指定记录,데이터set 길이必须严格等于 데이터RowSize |
easydb_del(db, idx) | idx | 삭제指定记录 |
easydb_clear(db) | 句柄 | 모두 지우기记录 |
3. 데이터记录控件「自定义」모드
데이터来源设为自定义时,系统不知道有多少行데이터,必须由两个回调提供:
- 记录数量回调
on_get_record_count(screen_id, control_id):返回总行数,内部调 easydb_get_count(g_db_handle) - 记录콘텐츠回调
on_get_record_row(screen_id, control_id, row):返回第 row 行的문자串콘텐츠
function on_get_record_count(screen_id, control_id)
if screen_id == 0 and control_id == 1 then
return db.getCnt(g_db_handle)
end
end
function on_get_record_row(screen_id, control_id, row)
local ret, msg = db.get(g_db_handle, row)
if ret == 0 then
return msg
end
end控件설정:데이터来源=自定义、문자编码=UTF8、翻页控制√、控制주소 LW4000、选中行通知√(LW4004,UINT32)——选中某行时索引写进 LW4004,增删改都靠它定位。
4. 적용:db.lua 句柄封装 + 增删改查
4.1 初始化(on_init)
function on_init()
dofile("db.lua")
_EN_ON_UP데이터_API_ = 0
-- 10MB 시작、不存在则创建、单条1000바이트、最多1000条
g_db_handle = db.열기(10*1024*1024, 1, 1000, 1000)
if g_db_handle == 0 then
print("ERROR: 无法열기데이터库!")
return
end
db.clear(g_db_handle) -- 지우기旧데이터(可选)
db.add(g_db_handle, "Alice;Engineer;30")
db.add(g_db_handle, "Bob;Technician;25")
db.add(g_db_handle, "Charlie;Manager;40")
db.add(g_db_handle, "Harden;Basketball players;36")
_EN_ON_UP데이터_API_ = 1
end记录형식「姓名;职业;年龄」,英文分号分隔,和表格控件분석规则一致,直接映射多列。
4.2 增删改(LW5000 按键分发)
function on_update(slave, vtype, addr)
if addr == 0x4004 then -- 选中行通知
local idx = get_uint32(VT_LW, addr)
local ret, msg = db.get(g_db_handle, idx)
if ret == 0 then
local parts = my_split(msg, ";")
if parts ~= nil then
set_uint16(VT_LW, 0x4530, idx) -- 记录当前选中索引
set_string(VT_LW, 0x4500, (parts[1] == nil) and "--" or parts[1])
set_string(VT_LW, 0x4510, (parts[2] == nil) and "--" or parts[2])
set_string(VT_LW, 0x4520, (parts[3] == nil) and "--" or parts[3])
end
show_dialog(1, 232, 33, 50) -- 弹窗显示详情
end
elseif addr == 0x5000 then
local key = get_uint16(VT_LW, addr)
if key == 0 then -- 추가
local name = get_string(VT_LW, 0x5010)
local position = get_string(VT_LW, 0x5020)
local age = get_string(VT_LW, 0x5030)
db.add(g_db_handle, name..";"..position..";"..age..";")
elseif key == 1 then -- 修改(改选中行)
local name = get_string(VT_LW, 0x4500)
local position = get_string(VT_LW, 0x4510)
local age = get_string(VT_LW, 0x4520)
local idx = get_uint16(VT_LW, 0x4530)
db.modify(g_db_handle, idx, name..";"..position..";"..age..";")
elseif key == 2 then -- 삭제(删选中行)
local idx = get_uint16(VT_LW, 0x4530)
db.del(g_db_handle, idx)
end
end
enddb.lua 封装层每个函数都做句柄체크섬 + 索引越界检查(idx = count 返回 -2),这是句柄驱动设计的표준姿势:不合法就直接返回错误码,绝不往下传。
四个坑:①flashaddr 必须避开엔지니어링자료/자료采样/操作记录/OTA 备份四区,直接操作 Flash 无隔离,选错주소데이터互相覆盖甚至变砖;②easydb_update 的 데이터set 길이必须严格等于创建时的 데이터RowSize,长了短了都会失败;③记录用英文分号 ; 分隔,和表格控件분석规则对齐,别用중국어分号;④句柄是全局生命周期자료,on_init 里开一次全程持有,操作前先체크섬句柄非 0、索引在范围内。定制固件才有这套 API,普通固件没有。
整理自 广州大彩科技 VisualHMI 개발문서(hmi-doc.gz-dc.com)LUA 튜토리얼「简易데이터库」,版权归大彩科技所有。
답글 작성