tsb_wavein_page.lua 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802
  1. --[[
  2. @module tsb_wavein_page
  3. @summary 波形输入页面
  4. @version 1.0
  5. @date 2026.03.18
  6. @author 李一玮
  7. @usage
  8. 本文件是波形输入页面,展示波形数据和控制功能。
  9. ]]
  10. local tsb_wavein_page = {}
  11. -- 页面UI元素
  12. local main_container = nil
  13. local scroll_container = nil
  14. local chart_timer = nil -- 数据推送定时器ID
  15. local page_active = false -- 页面是否活跃,用于定时器安全
  16. local common_ui = require("tsb_common_page")
  17. local chart = nil -- 图表对象
  18. local freq_label = nil -- 频率显示标签
  19. local vmax_label = nil -- 电压最大值标签
  20. local vmin_label = nil -- 电压最小值标签
  21. local trigger_threshold_input = nil -- 触发阈值输入框
  22. local visible_btn = nil -- 按钮可见性按钮
  23. local set_btn = nil -- 设置按钮
  24. local reset_btn = nil -- 重置按钮
  25. local label_btn = nil -- 标签按钮
  26. local trigger_type_btn = nil -- 触发类型按钮
  27. local trigger_mode_btn = nil -- 触发方式按钮
  28. local pulse_width_input = nil -- 脉宽触发输入框
  29. local time_scale_dropdown = nil -- 时间档位下拉框
  30. local run_control_btn = nil -- 运行控制按钮
  31. -- 控制参数
  32. local time_scale = "2ms" -- 时间档位
  33. local vertical_scale = "5V" -- 垂直档位
  34. local trigger_threshold = "0" -- 触发阈值
  35. local trigger_type = "上升沿" -- 触发类型:上升沿、下降沿、双边沿、脉宽触发
  36. local trigger_mode = "自动" -- 触发方式:自动、普通、单次
  37. local show_menu = false
  38. local vertical_scale_dropdown = nil
  39. local is_running = true -- 运行状态
  40. local last_x_offset = 0 -- 上一次的水平偏移值
  41. local last_t_offset = 0 -- 上一次的触发位置
  42. local label_x_offset = nil -- 水平偏移标签
  43. local tp_touch_subid = nil -- 触摸事件订阅ID
  44. -- 示波器可移动标签相关参数
  45. local show_labels = false -- 是否显示标签
  46. local step_size = 1 -- 标签移动步长
  47. local choose_step_btn = nil -- 步长选择按钮
  48. local trigger_line = nil -- 触发位置竖线
  49. local trigger_label = nil -- 触发位置标签"T"
  50. local trigger_line_color = 0xA8A8A8 -- 灰色
  51. local label_overlay = nil -- 标签覆盖层
  52. -- 更新触发位置竖线
  53. local function update_trigger_line(x_offset)
  54. -- 500个数据点映射到440像素宽度
  55. -- x_offset范围: 0-500,默认250(中间位置)
  56. -- 计算屏幕X坐标
  57. local screen_x = x_offset / 500 * 440
  58. -- 销毁旧的触发线
  59. if trigger_line then
  60. trigger_line:destroy()
  61. trigger_line = nil
  62. end
  63. -- 创建新的触发线(红色竖线)
  64. trigger_line = airui.shape({
  65. parent = chart,
  66. x = 0,
  67. y = 0,
  68. w = 430,
  69. h = 220,
  70. items = {
  71. {
  72. type = "line",
  73. x1 = screen_x, y1 = 0,
  74. x2 = screen_x, y2 = 230,
  75. color = trigger_line_color,
  76. width = 2,
  77. opacity = 80
  78. }
  79. }
  80. })
  81. -- 销毁旧的标签"T"
  82. if trigger_label then
  83. trigger_label:destroy()
  84. trigger_label = nil
  85. end
  86. -- 创建标签"T"
  87. trigger_label = airui.label({
  88. parent = main_container,
  89. text = "T",
  90. x = 10 + screen_x + 7, -- 居中显示
  91. y = 35,
  92. w = 14,
  93. h = 16,
  94. color = trigger_line_color,
  95. font_size = 14,
  96. })
  97. log.info("chart", "触发位置更新", "x_offset:", x_offset, "screen_x:", screen_x)
  98. end
  99. local label_msg_container = nil -- 标签消息容器
  100. local label_btn_container = nil -- 标签操作按钮容器
  101. local label_a_title = nil -- 标签A标题
  102. local label_b_title = nil -- 标签B标题
  103. local label_a_x = nil -- 标签A位置
  104. local label_b_x = nil -- 标签B位置
  105. local label_a_msg = nil -- 标签A消息
  106. local label_b_msg = nil -- 标签B消息
  107. local label_ab_msg = nil -- 标签AB消息
  108. local label_btn_a_left = nil -- 标签A左移按钮
  109. local label_btn_a_right = nil -- 标签A右移按钮
  110. local label_btn_b_left = nil -- 标签B左移按钮
  111. local label_btn_b_right = nil -- 标签B右移按钮
  112. local label_c_title = nil -- 标签C标题
  113. local label_d_title = nil -- 标签D标题
  114. local label_c_y = nil -- 标签C位置
  115. local label_d_y = nil -- 标签D位置
  116. local label_c_msg = nil -- 标签C消息
  117. local label_d_msg = nil -- 标签D消息
  118. local label_cd_msg = nil -- 标签CD消息
  119. local label_btn_c_up = nil -- 标签C上移按钮
  120. local label_btn_c_down = nil -- 标签C下移按钮
  121. local label_btn_d_up = nil -- 标签D上移按钮
  122. local label_btn_d_down = nil -- 标签D下移按钮
  123. local label_a_color = 0xD32F2F -- 复古红
  124. local label_b_color = 0x0277BD -- 湖蓝
  125. local label_c_color = 0x2E7D32 -- 墨绿
  126. local label_d_color = 0x7B1FA2 -- 深紫
  127. -- 引入uart1_msg模块
  128. local uart_send = require("uart1_msg")
  129. -- 发送ADC配置指令
  130. local function send_adc_config()
  131. -- 收集参数
  132. local config = {}
  133. -- 垂直档位(单位:mV)
  134. local vertical_gear_map = {
  135. ["1.5V"] = 15000,
  136. ["1V"] = 10000,
  137. ["500mV"] = 5000,
  138. ["200mV"] = 2000,
  139. ["100mV"] = 1000,
  140. ["50mv"] = 500,
  141. ["20mv"] = 200
  142. }
  143. config.vertical_gear = vertical_gear_map[vertical_scale] or 5000
  144. -- 时间档位(单位:us)
  145. local time_gear_map = {
  146. ["1s"] = 1000000,
  147. ["500ms"] = 500000,
  148. ["200ms"] = 200000,
  149. ["100ms"] = 100000,
  150. ["50ms"] = 50000,
  151. ["20ms"] = 20000,
  152. ["10ms"] = 10000,
  153. ["5ms"] = 5000,
  154. ["2ms"] = 2000,
  155. ["1ms"] = 1000,
  156. ["500us"] = 500,
  157. ["200us"] = 200,
  158. ["100us"] = 100,
  159. ["50us"] = 50
  160. }
  161. config.time_gear = time_gear_map[time_scale] or 1000
  162. -- 水平偏移
  163. if _G.x_offset == 0 then
  164. config.x_offset = 0 -- 回归原始
  165. elseif _G.x_offset > last_x_offset then
  166. config.x_offset = 2 -- 右移
  167. elseif _G.x_offset < last_x_offset then
  168. config.x_offset = 1 -- 左移
  169. else
  170. config.x_offset = 0
  171. end
  172. -- 更新上一次的x_offset值
  173. last_x_offset = _G.x_offset
  174. -- 垂直偏移
  175. config.y_offset = _G.y_offset
  176. -- 触发阈值(单位:mV)
  177. local threshold = tonumber(trigger_threshold_input:get_text()) or 2
  178. config.trigger_threshold = threshold * 1000
  179. -- 触发类型
  180. local trigger_type_map = {
  181. ["上升沿"] = 0,
  182. ["下降沿"] = 1,
  183. ["双边沿"] = 2,
  184. ["脉宽触发"] = 3
  185. }
  186. config.trigger_type = trigger_type_map[trigger_type] or 0
  187. -- 触发脉宽(单位:us)
  188. local pulse_width = tonumber(pulse_width_input:get_text()) or 200
  189. config.trigger_width = pulse_width
  190. -- 触发方式
  191. local trigger_method_map = {
  192. ["自动"] = 0,
  193. ["普通"] = 1,
  194. ["单次"] = 2
  195. }
  196. config.trigger_method = trigger_method_map[trigger_mode] or 0
  197. -- 运行控制
  198. config.run_control = is_running and 1 or 0
  199. -- 复位
  200. config.reset = 0
  201. -- 发送指令
  202. uart_send.send_adc_config(config)
  203. end
  204. -- 发送ADC动态操作指令
  205. local function send_adc_operate()
  206. -- 收集参数
  207. local config = {}
  208. -- 触发方式
  209. local trigger_method_map = {
  210. ["自动"] = 0,
  211. ["普通"] = 1,
  212. ["单次"] = 2
  213. }
  214. config.trigger_method = trigger_method_map[trigger_mode] or 0
  215. -- 运行控制
  216. config.run_control = is_running and 1 or 0
  217. -- 复位
  218. config.reset = 0
  219. -- 发送指令
  220. uart_send.send_adc_operate(config)
  221. end
  222. -- 更新水平偏移标签显示
  223. local function update_x_offset_label()
  224. local offset_value = _G.x_offset or 0
  225. local percent = math.abs(offset_value) * 10 -- 将 -10~10 转换为 0~100%
  226. local text
  227. if offset_value == 0 then
  228. text = "偏移 0%"
  229. elseif offset_value < 0 then
  230. text = string.format("左移 %d%%", percent)
  231. else
  232. text = string.format("右移 %d%%", percent)
  233. end
  234. if label_x_offset then
  235. label_x_offset:set_text(text)
  236. end
  237. end
  238. local function update_vertical_scale_dropdown()
  239. if not vertical_scale_dropdown then
  240. return
  241. end
  242. -- 反向映射:Y_FULL_SCALE 值到档位选项
  243. local scale_map = {
  244. [15] = 0, -- "15V"
  245. [10] = 1, -- "10V"
  246. [5] = 2, -- "5V"
  247. [2] = 3, -- "2V"
  248. [1] = 4, -- "1V"
  249. [0.5] = 5, -- "500mv"
  250. [0.2] = 6 -- "200mv"
  251. }
  252. local index = scale_map[_G.Y_FULL_SCALE] or 2 -- 默认5V
  253. vertical_scale_dropdown:set_selected(index)
  254. -- 同时更新 vertical_scale 变量
  255. local options = {"1.5V","1V", "500mV", "200mV", "100mV", "50mv", "20mv"}
  256. vertical_scale = options[index + 1]
  257. end
  258. local function update_time_scale_dropdown()
  259. if not time_scale_dropdown then
  260. return
  261. end
  262. -- 设置时间档位为2ms(索引8)
  263. local default_index = 8 -- 2ms
  264. time_scale_dropdown:set_selected(default_index)
  265. -- 同时更新 time_scale 变量
  266. local options = {"1s", "500ms", "200ms", "100ms", "50ms", "20ms", "10ms", "5ms", "2ms", "1ms", "500us", "200us", "100us", "50us"}
  267. time_scale = options[default_index + 1]
  268. end
  269. local function reset_all_settings()
  270. -- 重置全局变量
  271. _G.x_offset = 0
  272. _G.y_offset = 0
  273. _G.Y_FULL_SCALE = 5
  274. -- 重置垂直档位
  275. update_vertical_scale_dropdown()
  276. -- 重置时间档位
  277. update_time_scale_dropdown()
  278. -- 初始化时更新标签显示
  279. update_x_offset_label()
  280. -- 重置触发阈值输入框
  281. if trigger_threshold_input then
  282. trigger_threshold_input:set_text("2")
  283. end
  284. -- 重置脉宽触发输入框
  285. if pulse_width_input then
  286. pulse_width_input:set_text("200")
  287. end
  288. -- 重置触发类型
  289. trigger_type = "上升沿"
  290. if trigger_type_btn then
  291. trigger_type_btn:set_text("上升沿")
  292. end
  293. -- 重置触发方式
  294. trigger_mode = "自动"
  295. if trigger_mode_btn then
  296. trigger_mode_btn:set_text("自动")
  297. end
  298. -- 重置运行状态
  299. is_running = true
  300. if run_control_btn then
  301. run_control_btn:set_text("暂停")
  302. end
  303. -- 发送配置指令
  304. send_adc_config()
  305. send_adc_operate()
  306. end
  307. -- 创建UI
  308. function tsb_wavein_page.create_ui()
  309. main_container = airui.container({
  310. x = 0,
  311. y = 0,
  312. w = 480,
  313. h = 320,
  314. color = 0xFFFFFF
  315. })
  316. --------------------- 标题栏 ------------------------
  317. local title_bar = airui.container({
  318. parent = main_container,
  319. x = 0,
  320. y = 0,
  321. w = 480,
  322. h = 30,
  323. color = 0xFFD93D
  324. })
  325. airui.label({
  326. parent = title_bar,
  327. text = "波形输入",
  328. x = 200,
  329. y = 8,
  330. w = 80,
  331. h = 20,
  332. font_size = 16,
  333. color = 0xFFFFFF,
  334. })
  335. -- 标题栏公共信息展示
  336. common_ui.add_battery_display(title_bar)
  337. common_ui.create_back_button(title_bar, tsb_wavein_page.cleanup)
  338. ---------------------------------------------------
  339. local keyboard1 = airui.keyboard({
  340. x = 0,
  341. y = 0,
  342. w = 480,
  343. h = 160, -- x, y, 键盘默认打开ALIGN_BOTTOM_MID,位置从中下方开始计算
  344. mode = "numeric", -- 键盘模式,可选 "text"/"upper"/"lower"/"numeric"
  345. auto_hide = true, -- 自动隐藏键盘
  346. preview = true,
  347. preview_height = 35,
  348. bg_color = 0xf1f1f1, -- 键盘背景颜色为灰色,可选,不设置则透明
  349. on_commit = function() -- 确认事件回调,只有在按下确认键时才会触发
  350. log.info("keyboard", "commit")
  351. send_adc_config()
  352. end
  353. })
  354. chart = airui.chart({
  355. parent = main_container,
  356. x = 10,
  357. y = 40,
  358. w = 460,
  359. h = 250,
  360. y_min = 0,
  361. y_max = 100,
  362. point_count = 500,
  363. update_mode = "shift",
  364. line_color = 0x00b4ff,
  365. line_width = 2,
  366. hdiv = 11,
  367. vdiv = 11,
  368. bg_opa = 0
  369. })
  370. -- 控制区域(右侧)
  371. local control_container = airui.container({
  372. parent = main_container,
  373. x = 210,
  374. y = 40,
  375. w = 210,
  376. h = 250,
  377. color = 0xFFFFFF,
  378. radius = 5,
  379. border_width = 1,
  380. border_color = 0xDDDDDD,
  381. color_opacity = 255
  382. })
  383. control_container:hide()
  384. -- 订阅触摸事件,点击左侧区域关闭设置面板
  385. tp_touch_subid = sys.subscribe("TP_TOUCH", function(x, y)
  386. -- 只响应按下事件,避免重复触发
  387. if x >= 20 and x <= 200 and y >= 30 and y <= 280 then
  388. if show_menu then
  389. control_container:hide()
  390. show_menu = false
  391. log.info("chart", "点击左侧区域关闭设置面板")
  392. end
  393. end
  394. end)
  395. -- 隐藏/显示按钮(放在最顶层)
  396. visible_btn = airui.button({
  397. parent = main_container,
  398. text = "隐藏",
  399. x = 420,
  400. y = 40,
  401. w = 50,
  402. h = 30,
  403. style = {bg_opa = 0},
  404. on_click = function(self)
  405. if self:get_text() == "隐藏" then
  406. self:set_text("显示")
  407. scroll_container:hide()
  408. else
  409. self:set_text("隐藏")
  410. scroll_container:open()
  411. end
  412. end
  413. })
  414. -- 按钮容器(放在chart之后,确保在chart之上)
  415. scroll_container = airui.container({
  416. parent = main_container,
  417. x = 410,
  418. y = 70,
  419. w = 65,
  420. h = 190,
  421. color = 0xFFFFFFF,
  422. color_opacity =0
  423. })
  424. set_btn = airui.button({
  425. parent = scroll_container,
  426. text = "设置",
  427. x = 10,
  428. y = 5,
  429. w = 50,
  430. h = 30,
  431. --style = {bg_opa = 0},
  432. on_click = function()
  433. if show_menu then
  434. control_container:hide()
  435. show_menu = false
  436. else
  437. control_container:open()
  438. show_menu = true
  439. end
  440. end
  441. })
  442. reset_btn = airui.button({
  443. parent = scroll_container,
  444. text = "复位",
  445. x = 10,
  446. y = 40,
  447. w = 50,
  448. h = 30,
  449. --style = {bg_opa = 0},
  450. on_click = function()
  451. reset_all_settings()
  452. end
  453. })
  454. trigger_mode_btn = airui.button({
  455. parent = scroll_container,
  456. text = "自动",
  457. x = 10,
  458. y = 75,
  459. w = 50,
  460. h = 30,
  461. font_size = 14,
  462. --style = {bg_opa = 0},
  463. on_click = function(self)
  464. if trigger_mode == "自动" then
  465. trigger_mode = "普通"
  466. elseif trigger_mode == "普通" then
  467. trigger_mode = "单次"
  468. else
  469. trigger_mode = "自动"
  470. end
  471. self:set_text(trigger_mode)
  472. log.info("chart", "触发方式: " .. trigger_mode)
  473. send_adc_operate()
  474. end
  475. })
  476. -- 开始/暂停按钮
  477. run_control_btn = airui.button({
  478. parent = scroll_container,
  479. text = "暂停",
  480. x = 10,
  481. y = 110,
  482. w = 50,
  483. h = 30,
  484. font_size = 14,
  485. --style = {bg_opa = 0},
  486. on_click = function(self)
  487. if is_running then
  488. self:set_text("开始")
  489. is_running = false
  490. log.info("chart", "暂停")
  491. else
  492. self:set_text("暂停")
  493. is_running = true
  494. log.info("chart", "开始")
  495. end
  496. send_adc_operate()
  497. end
  498. })
  499. label_msg_container = airui.container({
  500. parent = main_container,
  501. x = 180,
  502. y = 40,
  503. w = 240,
  504. h = 80,
  505. color = 0xFFFFFF,
  506. radius = 8,
  507. border_width = 0,
  508. color_opacity = 0
  509. })
  510. label_a_msg = airui.label({
  511. parent = label_msg_container,
  512. text = "Xa: ms",
  513. x = 5,
  514. y = 10,
  515. w = 120,
  516. h = 20,
  517. font_size = 13,
  518. color = 0x000000,
  519. })
  520. label_b_msg = airui.label({
  521. parent = label_msg_container,
  522. text = "Xb: ms",
  523. x = 5,
  524. y = 30,
  525. w = 120,
  526. h = 20,
  527. font_size = 13,
  528. color = 0x000000,
  529. })
  530. label_ab_msg = airui.label({
  531. parent = label_msg_container,
  532. text = "Xab: ms",
  533. x = 5,
  534. y = 50,
  535. w = 120,
  536. h = 20,
  537. font_size = 13,
  538. color = 0x000000,
  539. })
  540. label_c_msg = airui.label({
  541. parent = label_msg_container,
  542. text = "Yc: mV",
  543. x = 130,
  544. y = 10,
  545. w = 110,
  546. h = 20,
  547. font_size = 13,
  548. color = 0x000000,
  549. })
  550. label_d_msg = airui.label({
  551. parent = label_msg_container,
  552. text = "Yd: mV",
  553. x = 130,
  554. y = 30,
  555. w = 110,
  556. h = 20,
  557. font_size = 13,
  558. color = 0x000000,
  559. })
  560. label_cd_msg = airui.label({
  561. parent = label_msg_container,
  562. text = "Ycd: mV",
  563. x = 130,
  564. y = 50,
  565. w = 110,
  566. h = 20,
  567. font_size = 13,
  568. color = 0x000000,
  569. })
  570. label_msg_container:hide()
  571. label_btn_container = airui.container({
  572. parent = main_container,
  573. x = 10,
  574. y = 130,
  575. w = 210,
  576. h = 150,
  577. color = 0xF111FF,
  578. radius = 8,
  579. border_width = 0,
  580. color_opacity = 0
  581. })
  582. -- 时间档位映射(单位:ms)
  583. local time_gear_map = {
  584. ["1s"] = 1000,
  585. ["500ms"] = 500,
  586. ["200ms"] = 200,
  587. ["100ms"] = 100,
  588. ["50ms"] = 50,
  589. ["20ms"] = 20,
  590. ["10ms"] = 10,
  591. ["5ms"] = 5,
  592. ["2ms"] = 2,
  593. ["1ms"] = 1,
  594. ["500us"] = 0.5,
  595. ["200us"] = 0.2,
  596. ["100us"] = 0.1,
  597. ["50us"] = 0.05
  598. }
  599. -- 垂直档位映射(单位:V)
  600. local vertical_gear_map = {
  601. ["50V"] = 50,
  602. ["20V"] = 20,
  603. ["10V"] = 10,
  604. ["5V"] = 5,
  605. ["2V"] = 2,
  606. ["1V"] = 1,
  607. ["500mV"] = 0.5,
  608. ["200mV"] = 0.2,
  609. ["100mV"] = 0.1,
  610. ["50mV"] = 0.05,
  611. ["20mV"] = 0.02,
  612. ["10mV"] = 0.01,
  613. ["5mV"] = 0.005
  614. }
  615. -- 更新标签位置函数
  616. local function update_label_positions()
  617. if not label_overlay then return end
  618. -- 销毁旧的overlay并重建
  619. label_overlay:destroy()
  620. -- 创建新的overlay
  621. label_overlay = airui.shape({
  622. parent = chart,
  623. x = 0,
  624. y = 0,
  625. w = 430,
  626. h = 220,
  627. items = {
  628. -- 标签A竖线
  629. {
  630. type = "line",
  631. x1 = label_a_x, y1 = 0,
  632. x2 = label_a_x, y2 = 250,
  633. color = label_a_color,
  634. width = 2,
  635. opacity = 255,
  636. dash_width = 2,
  637. dash_gap = 2,
  638. },
  639. -- 标签B竖线
  640. {
  641. type = "line",
  642. x1 = label_b_x, y1 = 0,
  643. x2 = label_b_x, y2 = 250,
  644. color = label_b_color,
  645. width = 2,
  646. opacity = 255,
  647. dash_width = 2,
  648. dash_gap = 2,
  649. },
  650. -- 标签C竖线
  651. {
  652. type = "line",
  653. x1 = 0, y1 = label_c_y,
  654. x2 = 430, y2 = label_c_y,
  655. color = label_c_color,
  656. width = 2,
  657. opacity = 255,
  658. dash_width = 2,
  659. dash_gap = 2,
  660. },
  661. -- 标签D竖线
  662. {
  663. type = "line",
  664. x1 = 0, y1 = label_d_y,
  665. x2 = 430, y2 = label_d_y,
  666. color = label_d_color,
  667. width = 2,
  668. opacity = 255,
  669. dash_width = 2,
  670. dash_gap = 2,
  671. }
  672. }
  673. })
  674. -- 更新标签A文字位置
  675. if label_a_title then
  676. label_a_title:destroy()
  677. end
  678. label_a_title = airui.label({
  679. parent = main_container,
  680. text = "A",
  681. x = 10 + label_a_x + 6,
  682. y = 30,
  683. w = 14,
  684. h = 16,
  685. color = label_a_color,
  686. font_size = 14,
  687. })
  688. -- 更新标签B文字位置
  689. if label_b_title then
  690. label_b_title:destroy()
  691. end
  692. label_b_title = airui.label({
  693. parent = main_container,
  694. text = "B",
  695. x = 10 + label_b_x + 6,
  696. y = 30,
  697. w = 14,
  698. h = 16,
  699. color = label_b_color,
  700. font_size = 14,
  701. })
  702. -- 更新标签C文字位置
  703. if label_c_title then
  704. label_c_title:destroy()
  705. end
  706. label_c_title = airui.label({
  707. parent = main_container,
  708. text = "C",
  709. x = 5,
  710. y = 40 + label_c_y,
  711. w = 14,
  712. h = 16,
  713. color = label_c_color,
  714. font_size = 14,
  715. })
  716. -- 更新标签D文字位置
  717. if label_d_title then
  718. label_d_title:destroy()
  719. end
  720. label_d_title = airui.label({
  721. parent = main_container,
  722. text = "D",
  723. x = 5,
  724. y = 40 + label_d_y,
  725. w = 14,
  726. h = 16,
  727. color = label_d_color,
  728. font_size = 14,
  729. })
  730. -- 计算并更新时间显示(标签A和B)
  731. local div_time = time_gear_map[time_scale] or 2 -- 每格时间(ms)
  732. local px_per_div_x = 44 -- 横向每格像素数
  733. local px_per_ms = px_per_div_x / div_time -- 每ms对应的像素数
  734. -- 计算Xa(以最左边为起点)
  735. local xa_ms = label_a_x / px_per_ms
  736. -- 计算Xb(以最左边为起点)
  737. local xb_ms = label_b_x / px_per_ms
  738. -- 计算Xab
  739. local xab_ms = math.abs(xb_ms - xa_ms)
  740. -- 获取最大绝对值用于确定统一单位
  741. local max_val_x = math.max(math.abs(xa_ms), math.abs(xb_ms), xab_ms)
  742. -- 根据最大值确定统一单位
  743. local unit_x
  744. if max_val_x >= 1000 then
  745. unit_x = "s"
  746. xa_ms = xa_ms / 1000
  747. xb_ms = xb_ms / 1000
  748. xab_ms = xab_ms / 1000
  749. elseif max_val_x >= 1 then
  750. unit_x = "ms"
  751. else
  752. unit_x = "us"
  753. xa_ms = xa_ms * 1000
  754. xb_ms = xb_ms * 1000
  755. xab_ms = xab_ms * 1000
  756. end
  757. -- 更新时间标签显示
  758. if unit_x == "s" then
  759. label_a_msg:set_text(string.format("Xa: %.3fs", xa_ms))
  760. label_b_msg:set_text(string.format("Xb: %.3fs", xb_ms))
  761. label_ab_msg:set_text(string.format("Xab: %.3fs", xab_ms))
  762. elseif unit_x == "ms" then
  763. label_a_msg:set_text(string.format("Xa: %.3fms", xa_ms))
  764. label_b_msg:set_text(string.format("Xb: %.3fms", xb_ms))
  765. label_ab_msg:set_text(string.format("Xab: %.3fms", xab_ms))
  766. else
  767. label_a_msg:set_text(string.format("Xa: %.0fus", xa_ms))
  768. label_b_msg:set_text(string.format("Xb: %.0fus", xb_ms))
  769. label_ab_msg:set_text(string.format("Xab: %.0fus", xab_ms))
  770. end
  771. -- 计算并更新电压显示(标签C和D)
  772. local div_voltage = vertical_gear_map[vertical_scale] or 1 -- 每格电压(V)
  773. local px_per_div_y = 23 -- 纵向每格像素数
  774. local px_per_v = px_per_div_y / div_voltage -- 每V对应的像素数
  775. -- 计算Yc(以最上方为起点,y=0时为最大电压)
  776. local yc_v = (230 - label_c_y) / px_per_v -- 230为最大y位置(10格 × 23px/格)
  777. -- 计算Yd
  778. local yd_v = (230 - label_d_y) / px_per_v
  779. -- 计算Ycd
  780. local ycd_v = math.abs(yd_v - yc_v)
  781. -- 获取最大绝对值用于确定统一单位
  782. local max_val_y = math.max(math.abs(yc_v), math.abs(yd_v), ycd_v)
  783. -- 根据最大值确定统一单位
  784. local unit_y
  785. if max_val_y >= 1 then
  786. unit_y = "V"
  787. elseif max_val_y >= 0.001 then
  788. unit_y = "mV"
  789. yc_v = yc_v * 1000
  790. yd_v = yd_v * 1000
  791. ycd_v = ycd_v * 1000
  792. else
  793. unit_y = "uV"
  794. yc_v = yc_v * 1000000
  795. yd_v = yd_v * 1000000
  796. ycd_v = ycd_v * 1000000
  797. end
  798. -- 更新电压标签显示(保留2位小数)
  799. if unit_y == "V" then
  800. label_c_msg:set_text(string.format("Yc: %.2fV", yc_v))
  801. label_d_msg:set_text(string.format("Yd: %.2fV", yd_v))
  802. label_cd_msg:set_text(string.format("Ycd: %.2fV", ycd_v))
  803. elseif unit_y == "mV" then
  804. label_c_msg:set_text(string.format("Yc: %.2fmV", yc_v))
  805. label_d_msg:set_text(string.format("Yd: %.2fmV", yd_v))
  806. label_cd_msg:set_text(string.format("Ycd: %.2fmV", ycd_v))
  807. else
  808. label_c_msg:set_text(string.format("Yc: %.0fuV", yc_v))
  809. label_d_msg:set_text(string.format("Yd: %.0fuV", yd_v))
  810. label_cd_msg:set_text(string.format("Ycd: %.0fuV", ycd_v))
  811. end
  812. end
  813. label_btn_a_left = airui.button({
  814. parent = label_btn_container,
  815. text = "A左移",
  816. x = 5,
  817. y = 5,
  818. w = 60,
  819. h = 30,
  820. --style = {bg_opa = 0},
  821. on_click = function()
  822. if label_a_x > 0 then
  823. label_a_x = label_a_x - step_size
  824. update_label_positions()
  825. log.info("chart", "标签A左移", "位置:", label_a_x)
  826. end
  827. end
  828. })
  829. label_btn_a_right = airui.button({
  830. parent = label_btn_container,
  831. text = "A右移",
  832. x = 70,
  833. y = 5,
  834. w = 60,
  835. h = 30,
  836. --style = {bg_opa = 0},
  837. on_click = function()
  838. if label_a_x < 430 then
  839. label_a_x = label_a_x + step_size
  840. update_label_positions()
  841. log.info("chart", "标签A右移", "位置:", label_a_x)
  842. end
  843. end
  844. })
  845. label_btn_b_left = airui.button({
  846. parent = label_btn_container,
  847. text = "B左移",
  848. x = 5,
  849. y = 40,
  850. w = 60,
  851. h = 30,
  852. --style = {bg_opa = 0},
  853. on_click = function()
  854. if label_b_x > 0 then
  855. label_b_x = label_b_x - step_size
  856. update_label_positions()
  857. log.info("chart", "标签B左移", "位置:", label_b_x)
  858. end
  859. end
  860. })
  861. label_btn_b_right = airui.button({
  862. parent = label_btn_container,
  863. text = "B右移",
  864. x = 70,
  865. y = 40,
  866. w = 60,
  867. h = 30,
  868. --style = {bg_opa = 0},
  869. on_click = function()
  870. if label_b_x < 430 then
  871. label_b_x = label_b_x + step_size
  872. update_label_positions()
  873. log.info("chart", "标签B右移", "位置:", label_b_x)
  874. end
  875. end
  876. })
  877. label_btn_c_up = airui.button({
  878. parent = label_btn_container,
  879. text = "C上移",
  880. x = 5,
  881. y = 75,
  882. w = 60,
  883. h = 30,
  884. --style = {bg_opa = 0},
  885. on_click = function()
  886. if label_c_y > 0 then
  887. label_c_y = label_c_y - step_size
  888. update_label_positions()
  889. log.info("chart", "标签C上移", "位置:", label_c_y)
  890. end
  891. end
  892. })
  893. label_btn_c_down = airui.button({
  894. parent = label_btn_container,
  895. text = "C下移",
  896. x = 70,
  897. y = 75,
  898. w = 60,
  899. h = 30,
  900. --style = {bg_opa = 0},
  901. on_click = function()
  902. if label_c_y < 224 then
  903. label_c_y = label_c_y + step_size
  904. update_label_positions()
  905. log.info("chart", "标签C下移", "位置:", label_c_y)
  906. end
  907. end
  908. })
  909. label_btn_d_up = airui.button({
  910. parent = label_btn_container,
  911. text = "D上移",
  912. x = 5,
  913. y = 110,
  914. w = 60,
  915. h = 30,
  916. --style = {bg_opa = 0},
  917. on_click = function()
  918. if label_d_y > 0 then
  919. label_d_y = label_d_y - step_size
  920. update_label_positions()
  921. log.info("chart", "标签D上移", "位置:", label_d_y)
  922. end
  923. end
  924. })
  925. label_btn_d_down = airui.button({
  926. parent = label_btn_container,
  927. text = "D下移",
  928. x = 70,
  929. y = 110,
  930. w = 60,
  931. h = 30,
  932. --style = {bg_opa = 0},
  933. on_click = function()
  934. if label_d_y < 224 then
  935. label_d_y = label_d_y + step_size
  936. update_label_positions()
  937. log.info("chart", "标签D下移", "位置:", label_d_y)
  938. end
  939. end
  940. })
  941. choose_step_btn = airui.button({
  942. parent = label_btn_container,
  943. text = "步长:1",
  944. x = 135,
  945. y = 110,
  946. w = 70,
  947. h = 30,
  948. --style = {bg_opa = 0},
  949. on_click = function(self)
  950. -- 步长档位列表
  951. local step_sizes = {1, 5, 20, 50}
  952. -- 找到当前步长的索引
  953. local current_index = 1
  954. for i, size in ipairs(step_sizes) do
  955. if size == step_size then
  956. current_index = i
  957. break
  958. end
  959. end
  960. -- 切换到下一个步长(循环)
  961. local next_index = current_index % #step_sizes + 1
  962. step_size = step_sizes[next_index]
  963. -- 更新按钮显示文字
  964. self:set_text(string.format("步长:%d", step_size))
  965. log.info("chart", "步长切换", "当前步长:", step_size)
  966. end
  967. })
  968. label_btn_container:hide()
  969. label_btn = airui.button({
  970. parent = scroll_container,
  971. text = "标签",
  972. x = 10,
  973. y = 145,
  974. w = 50,
  975. h = 30,
  976. --style = {bg_opa = 0},
  977. on_click = function(self)
  978. if show_labels then
  979. self:set_text("标签")
  980. show_labels = false
  981. log.info("chart", "关闭标签")
  982. label_msg_container:hide()
  983. label_btn_container:hide()
  984. -- 销毁overlay
  985. if label_overlay then
  986. label_overlay:destroy()
  987. label_overlay = nil
  988. end
  989. -- 销毁标签文字
  990. if label_a_title then
  991. label_a_title:destroy()
  992. label_a_title = nil
  993. end
  994. if label_b_title then
  995. label_b_title:destroy()
  996. label_b_title = nil
  997. end
  998. if label_c_title then
  999. label_c_title:destroy()
  1000. label_c_title = nil
  1001. end
  1002. if label_d_title then
  1003. label_d_title:destroy()
  1004. label_d_title = nil
  1005. end
  1006. else
  1007. self:set_text("关标")
  1008. show_labels = true
  1009. log.info("chart", "开启标签")
  1010. label_msg_container:open()
  1011. label_btn_container:open()
  1012. -- 标签位置变量(可配置)
  1013. label_a_x = 200 -- 标签A的X位置
  1014. label_b_x = 300 -- 标签B的X位置
  1015. label_c_y = 100
  1016. label_d_y = 150
  1017. -- 创建overlay,包含A、B两根竖线(父容器为chart,避免覆盖按钮)
  1018. label_overlay = airui.shape({
  1019. parent = chart,
  1020. x = 0,
  1021. y = 0,
  1022. w = 430,
  1023. h = 220,
  1024. items = {
  1025. -- 标签A竖线
  1026. {
  1027. type = "line",
  1028. x1 = label_a_x, y1 = 0,
  1029. x2 = label_a_x, y2 = 250,
  1030. color = label_a_color,
  1031. width = 2,
  1032. opacity = 255,
  1033. dash_width = 2,
  1034. dash_gap = 2,
  1035. },
  1036. -- 标签B竖线
  1037. {
  1038. type = "line",
  1039. x1 = label_b_x, y1 = 0,
  1040. x2 = label_b_x, y2 = 250,
  1041. color = label_b_color,
  1042. width = 2,
  1043. opacity = 255,
  1044. dash_width = 2,
  1045. dash_gap = 2,
  1046. },
  1047. -- 标签C横线
  1048. {
  1049. type = "line",
  1050. x1 = 0, y1 = label_c_y,
  1051. x2 = 430, y2 = label_c_y,
  1052. color = label_c_color,
  1053. width = 2,
  1054. opacity = 255,
  1055. dash_width = 2,
  1056. dash_gap = 2,
  1057. },
  1058. -- 标签D横线
  1059. {
  1060. type = "line",
  1061. x1 = 0, y1 = label_d_y,
  1062. x2 = 430, y2 = label_d_y,
  1063. color = label_d_color,
  1064. width = 2,
  1065. opacity = 255,
  1066. dash_width = 2,
  1067. dash_gap = 2,
  1068. }
  1069. }
  1070. })
  1071. -- 创建标签A文字
  1072. label_a_title = airui.label({
  1073. parent = main_container,
  1074. text = "A",
  1075. x = 10 + label_a_x + 6,
  1076. y = 35,
  1077. w = 14,
  1078. h = 16,
  1079. color = label_a_color,
  1080. font_size = 14,
  1081. })
  1082. -- 创建标签B文字
  1083. label_b_title = airui.label({
  1084. parent = main_container,
  1085. text = "B",
  1086. x = 10 + label_b_x + 6,
  1087. y = 35,
  1088. w = 14,
  1089. h = 16,
  1090. color = label_b_color,
  1091. font_size = 14,
  1092. })
  1093. -- 创建标签C文字
  1094. label_c_title = airui.label({
  1095. parent = main_container,
  1096. text = "C",
  1097. x = 10,
  1098. y = label_c_y + 40,
  1099. w = 14,
  1100. h = 16,
  1101. color = label_c_color,
  1102. font_size = 14,
  1103. })
  1104. -- 创建标签D文字
  1105. label_d_title = airui.label({
  1106. parent = main_container,
  1107. text = "D",
  1108. x = 10,
  1109. y = label_d_y + 40,
  1110. w = 14,
  1111. h = 16,
  1112. color = label_d_color,
  1113. font_size = 14,
  1114. })
  1115. end
  1116. end
  1117. })
  1118. -- 添加选项卡
  1119. local tabview = airui.tabview({
  1120. parent = control_container,
  1121. x = 2,
  1122. y = 2,
  1123. w = 205,
  1124. h = 245,
  1125. tabs = {"基础设置", "触发设置"},
  1126. active = 0,
  1127. page_style = {
  1128. tabbar_size = 40,
  1129. pad = { method = airui.TABVIEW_PAD_ALL, value = 0 },
  1130. bg_opa = 255,
  1131. },
  1132. })
  1133. -- 第一页:基础设置
  1134. local tab1 = tabview:get_content(0)
  1135. local control_y1 = 10
  1136. -- 时间档位
  1137. airui.label({
  1138. parent = tab1,
  1139. text = "时间档位",
  1140. x = 10,
  1141. y = control_y1 + 5,
  1142. w = 70,
  1143. h = 20,
  1144. font_size = 12,
  1145. color = 0x000000,
  1146. })
  1147. time_scale_dropdown = airui.dropdown({
  1148. parent = tab1,
  1149. x = 80,
  1150. y = control_y1,
  1151. w = 110,
  1152. h = 25,
  1153. options = {"1s", "500ms", "200ms", "100ms", "50ms", "20ms", "10ms", "5ms", "2ms", "1ms", "500us", "200us", "100us", "50us"},
  1154. default_index = 8, -- 默认2ms
  1155. on_change = function(self, idx)
  1156. local options = {"1s", "500ms", "200ms", "100ms", "50ms", "20ms", "10ms", "5ms", "2ms", "1ms", "500us", "200us", "100us", "50us"}
  1157. time_scale = options[idx + 1]
  1158. log.info("chart", "时间档位: " .. time_scale)
  1159. send_adc_config()
  1160. end
  1161. })
  1162. control_y1 = control_y1 + 40
  1163. -- 垂直档位
  1164. airui.label({
  1165. parent = tab1,
  1166. text = "垂直档位",
  1167. x = 10,
  1168. y = control_y1 + 5,
  1169. w = 90,
  1170. h = 20,
  1171. font_size = 12,
  1172. color = 0x000000,
  1173. })
  1174. vertical_scale_dropdown = airui.dropdown({
  1175. parent = tab1,
  1176. x = 80,
  1177. y = control_y1,
  1178. w = 110,
  1179. h = 25,
  1180. options = {"1.5V","1V", "500mV", "200mV", "100mV", "50mv", "20mv"},
  1181. default_index = 2, -- 默认5V
  1182. on_change = function(self, idx)
  1183. local options = {"1.5V","1V","500mV", "200mV", "100mV", "50mv", "20mv"}
  1184. vertical_scale = options[idx + 1]
  1185. -- 根据选择的档位更新全局变量
  1186. local scale_map = {
  1187. ["1.5V"] = 15,
  1188. ["1V"] = 10,
  1189. ["500mV"] = 5,
  1190. ["200mV"] = 2,
  1191. ["100mV"] = 1,
  1192. ["50mv"] = 0.5,
  1193. ["20mv"] = 0.2
  1194. }
  1195. _G.Y_FULL_SCALE = scale_map[vertical_scale] or 5
  1196. log.info("chart", "垂直档位: " .. vertical_scale, "Y_FULL_SCALE: " .. _G.Y_FULL_SCALE)
  1197. send_adc_config()
  1198. end
  1199. })
  1200. control_y1 = control_y1 + 40
  1201. -- 水平偏移
  1202. airui.label({
  1203. parent = tab1,
  1204. text = "水平偏移",
  1205. x = 10,
  1206. y = control_y1,
  1207. w = 110,
  1208. h = 20,
  1209. font_size = 12,
  1210. color = 0x000000,
  1211. })
  1212. local x_offset_container = airui.container({
  1213. parent = tab1,
  1214. x = 10,
  1215. y = control_y1 + 20,
  1216. w = 190,
  1217. h = 30,
  1218. color = 0xFFFFFF,
  1219. radius = 4,
  1220. })
  1221. airui.button({
  1222. parent = x_offset_container,
  1223. text = "←",
  1224. x = 10,
  1225. y = 2,
  1226. w = 75,
  1227. h = 25,
  1228. on_click = function()
  1229. if _G.x_offset > -10 then
  1230. _G.x_offset = _G.x_offset - 1 -- 左移
  1231. log.info("chart", "水平偏移左", "x_offset: " .. _G.x_offset)
  1232. update_x_offset_label() -- 更新标签显示
  1233. send_adc_config()
  1234. else
  1235. log.info("chart", "水平偏移已达到左极限")
  1236. end
  1237. end
  1238. })
  1239. airui.button({
  1240. parent = x_offset_container,
  1241. text = "→",
  1242. x = 110,
  1243. y = 2,
  1244. w = 75,
  1245. h = 25,
  1246. on_click = function()
  1247. if _G.x_offset < 10 then
  1248. _G.x_offset = _G.x_offset + 1 -- 右移
  1249. log.info("chart", "水平偏移右", "x_offset: " .. _G.x_offset)
  1250. update_x_offset_label() -- 更新标签显示
  1251. send_adc_config()
  1252. else
  1253. log.info("chart", "水平偏移已达到右极限")
  1254. end
  1255. end
  1256. })
  1257. label_x_offset = airui.label({
  1258. parent = tab1,
  1259. text = "偏移 0%",
  1260. x = 130,
  1261. y = control_y1,
  1262. w = 70,
  1263. h = 20,
  1264. font_size = 12,
  1265. color = 0x000000,
  1266. })
  1267. control_y1 = control_y1 + 60
  1268. -- 垂直偏移
  1269. airui.label({
  1270. parent = tab1,
  1271. text = "垂直偏移",
  1272. x = 10,
  1273. y = control_y1,
  1274. w = 110,
  1275. h = 20,
  1276. font_size = 12,
  1277. color = 0x000000,
  1278. })
  1279. local y_offset_container = airui.container({
  1280. parent = tab1,
  1281. x = 10,
  1282. y = control_y1 + 20,
  1283. w = 190,
  1284. h = 30,
  1285. color = 0xFFFFFF,
  1286. radius = 4,
  1287. })
  1288. airui.button({
  1289. parent = y_offset_container,
  1290. text = "↑",
  1291. x = 10,
  1292. y = 2,
  1293. w = 75,
  1294. h = 25,
  1295. on_click = function()
  1296. _G.y_offset = _G.y_offset + 5 -- 上移,值增大
  1297. log.info("chart", "垂直偏移上", "y_offset: " .. _G.y_offset)
  1298. send_adc_config()
  1299. end
  1300. })
  1301. airui.button({
  1302. parent = y_offset_container,
  1303. text = "↓",
  1304. x = 110,
  1305. y = 2,
  1306. w = 75,
  1307. h = 25,
  1308. on_click = function()
  1309. _G.y_offset = _G.y_offset - 5 -- 下移,值减小
  1310. log.info("chart", "垂直偏移下", "y_offset: " .. _G.y_offset)
  1311. send_adc_config()
  1312. end
  1313. })
  1314. -- 第二页:触发设置
  1315. local tab2 = tabview:get_content(1)
  1316. local control_y2 = 25
  1317. -- 触发阈值
  1318. airui.label({
  1319. parent = tab2,
  1320. text = "触发阈值",
  1321. x = 10,
  1322. y = control_y2 + 10,
  1323. w = 60,
  1324. h = 20,
  1325. font_size = 14,
  1326. color = 0x000000,
  1327. })
  1328. trigger_threshold_input = airui.textarea({
  1329. parent = tab2,
  1330. x = 80,
  1331. y = control_y2 + 5,
  1332. w = 80,
  1333. h = 25,
  1334. text = "2",
  1335. max_len = 5,
  1336. keyboard = keyboard1,
  1337. on_text_change = function(txt)
  1338. log.info("text changed:", txt)
  1339. end
  1340. })
  1341. airui.label({
  1342. parent = tab2,
  1343. text = "V",
  1344. x = 165,
  1345. y = control_y2 + 10,
  1346. w = 30,
  1347. h = 20,
  1348. font_size = 14,
  1349. color = 0x000000,
  1350. })
  1351. control_y2 = control_y2 + 40
  1352. -- 触发类型
  1353. airui.label({
  1354. parent = tab2,
  1355. text = "触发类型",
  1356. x = 10,
  1357. y = control_y2 + 30,
  1358. w = 60,
  1359. h = 20,
  1360. font_size = 14,
  1361. color = 0x000000,
  1362. })
  1363. trigger_type_btn = airui.button({
  1364. parent = tab2,
  1365. text = "上升沿",
  1366. x = 80,
  1367. y = control_y2 + 25,
  1368. w = 80,
  1369. h = 25,
  1370. font_size = 14,
  1371. on_click = function(self)
  1372. if trigger_type == "上升沿" then
  1373. trigger_type = "下降沿"
  1374. elseif trigger_type == "下降沿" then
  1375. trigger_type = "双边沿"
  1376. elseif trigger_type == "双边沿" then
  1377. trigger_type = "脉宽触发"
  1378. elseif trigger_type == "脉宽触发" then
  1379. trigger_type = "上升沿"
  1380. end
  1381. self:set_text(trigger_type)
  1382. log.info("chart", "触发类型: " .. trigger_type)
  1383. send_adc_config()
  1384. end
  1385. })
  1386. control_y2 = control_y2 + 80
  1387. -- 脉宽触发
  1388. airui.label({
  1389. parent = tab2,
  1390. text = "脉宽触发",
  1391. x = 10,
  1392. y = control_y2 + 10,
  1393. w = 60,
  1394. h = 20,
  1395. font_size = 14,
  1396. color = 0x000000,
  1397. })
  1398. pulse_width_input = airui.textarea({
  1399. parent = tab2,
  1400. x = 80,
  1401. y = control_y2 + 5,
  1402. w = 80,
  1403. h = 25,
  1404. text = "200",
  1405. max_len = 5,
  1406. keyboard = keyboard1,
  1407. })
  1408. airui.label({
  1409. parent = tab2,
  1410. text = "us",
  1411. x = 165,
  1412. y = control_y2 + 10,
  1413. w = 30,
  1414. h = 20,
  1415. font_size = 14,
  1416. color = 0x000000,
  1417. })
  1418. -- 信息显示区域(图表下方)
  1419. local info_container = airui.container({
  1420. parent = main_container,
  1421. x = 10,
  1422. y = 40,
  1423. w = 160,
  1424. h = 80,
  1425. color = 0xFFFFFF,
  1426. radius = 8,
  1427. border_width = 0,
  1428. color_opacity = 0
  1429. })
  1430. airui.label({
  1431. parent = info_container,
  1432. text = "频率:",
  1433. x = 5,
  1434. y = 10,
  1435. w = 40,
  1436. h = 20,
  1437. font_size = 13,
  1438. color = 0x000000,
  1439. })
  1440. freq_label = airui.label({
  1441. parent = info_container,
  1442. text = "0 Hz",
  1443. x = 60,
  1444. y = 10,
  1445. w = 100,
  1446. h = 20,
  1447. font_size = 13,
  1448. color = 0x000000,
  1449. })
  1450. airui.label({
  1451. parent = info_container,
  1452. text = "Vmax:",
  1453. x = 5,
  1454. y = 30,
  1455. w = 60,
  1456. h = 20,
  1457. font_size = 13,
  1458. color = 0x000000,
  1459. })
  1460. vmax_label = airui.label({
  1461. parent = info_container,
  1462. text = "0 mV",
  1463. x = 60,
  1464. y = 30,
  1465. w = 65,
  1466. h = 20,
  1467. font_size = 13,
  1468. color = 0x000000,
  1469. })
  1470. airui.label({
  1471. parent = info_container,
  1472. text = "Vmin:",
  1473. x = 5,
  1474. y = 50,
  1475. w = 60,
  1476. h = 20,
  1477. font_size = 13,
  1478. color = 0x000000,
  1479. })
  1480. vmin_label = airui.label({
  1481. parent = info_container,
  1482. text = "0 mV",
  1483. x = 60,
  1484. y = 50,
  1485. w = 65,
  1486. h = 20,
  1487. font_size = 13,
  1488. color = 0x000000,
  1489. })
  1490. -- 底部信息
  1491. common_ui.create_status_bar(main_container)
  1492. end
  1493. local adc_wave_subid = nil
  1494. local function subscribe_adc_wave()
  1495. -- 先注销旧订阅,防止重复
  1496. if adc_wave_subid then
  1497. sys.unsubscribe(adc_wave_subid)
  1498. end
  1499. -- 绑定订阅
  1500. adc_wave_subid = sys.subscribe("ADC_WAVE_DATA", function(wave_data)
  1501. -- 只有页面激活 + 图表存在 才更新
  1502. if not page_active or not chart then
  1503. return
  1504. end
  1505. -- 校验数据
  1506. if not wave_data or #wave_data ~= 500 then
  1507. log.error("chart","波形长度错误!期望500,实际:", #wave_data)
  1508. return
  1509. end
  1510. chart:set_values(1, wave_data)
  1511. --log.info("chart","500点波形更新成功!")
  1512. end)
  1513. log.info("chart","ADC波形订阅已启动")
  1514. end
  1515. local adc_msg_subid = nil
  1516. local function subscribe_adc_msg()
  1517. -- 先注销旧订阅,防止重复
  1518. if adc_msg_subid then
  1519. sys.unsubscribe(adc_msg_subid)
  1520. end
  1521. -- 绑定订阅
  1522. adc_msg_subid = sys.subscribe("ADC_DATA_UPDATE", function(data)
  1523. if not data then return end
  1524. -- 更新频率标签
  1525. if freq_label then
  1526. local freq = data.frequency
  1527. local freq_str, unit
  1528. if freq >= 1000 then
  1529. freq_str = string.format("%.2f", freq / 1000)
  1530. unit = "kHz"
  1531. else
  1532. freq_str = tostring(freq)
  1533. unit = "Hz"
  1534. end
  1535. freq_label:set_text(freq_str .. " " .. unit)
  1536. end
  1537. -- 更新电压最大值标签
  1538. if vmax_label then
  1539. local max_vol = data.max_vol
  1540. local vol_str, unit
  1541. if max_vol >= 1000 then
  1542. vol_str = string.format("%.2f", max_vol / 1000)
  1543. unit = "V"
  1544. else
  1545. vol_str = tostring(max_vol)
  1546. unit = "mV"
  1547. end
  1548. vmax_label:set_text(vol_str .. " " .. unit)
  1549. end
  1550. -- 更新电压最小值标签
  1551. if vmin_label then
  1552. local min_vol = data.min_vol
  1553. local vol_str, unit
  1554. if min_vol >= 1000 then
  1555. vol_str = string.format("%.2f", min_vol / 1000)
  1556. unit = "V"
  1557. else
  1558. vol_str = tostring(min_vol)
  1559. unit = "mV"
  1560. end
  1561. vmin_label:set_text(vol_str .. " " .. unit)
  1562. end
  1563. -- 更新触发位置竖线
  1564. if data.x_offset ~= nil and page_active and data.x_offset ~= last_t_offset then
  1565. last_t_offset = data.x_offset
  1566. update_trigger_line(data.x_offset)
  1567. end
  1568. end)
  1569. end
  1570. -- 初始化页面
  1571. function tsb_wavein_page.init(params)
  1572. tsb_wavein_page.create_ui()
  1573. page_active = true
  1574. subscribe_adc_wave()
  1575. -- 创建初始触发线(默认位置250,即中间位置)
  1576. update_trigger_line(250)
  1577. subscribe_adc_msg()
  1578. -- 首次初始化时发送一次配置指令
  1579. -- 使用定时器延迟发送
  1580. sys.timerStart(function()
  1581. -- 先发送一个同步字节,确保串口完全就绪
  1582. -- 短暂延时后发送实际配置
  1583. reset_all_settings()
  1584. end, 100)
  1585. end
  1586. -- 清理页面
  1587. function tsb_wavein_page.cleanup()
  1588. page_active = false
  1589. -- 停止ADC运行
  1590. is_running = false
  1591. send_adc_operate() -- 发送停止指令
  1592. log.info("chart", "ADC已停止运行")
  1593. if chart_timer then
  1594. sys.timerStop(chart_timer)
  1595. chart_timer = nil
  1596. end
  1597. if adc_msg_subid then
  1598. sys.unsubscribe(adc_msg_subid)
  1599. adc_msg_subid = nil
  1600. end
  1601. if adc_wave_subid then
  1602. sys.unsubscribe(adc_wave_subid)
  1603. adc_wave_subid = nil
  1604. end
  1605. if tp_touch_subid then
  1606. sys.unsubscribe(tp_touch_subid)
  1607. tp_touch_subid = nil
  1608. end
  1609. if main_container then
  1610. main_container:destroy()
  1611. main_container = nil
  1612. scroll_container = nil
  1613. chart = nil
  1614. freq_label = nil
  1615. vmax_label = nil
  1616. vmin_label = nil
  1617. trigger_threshold_input = nil
  1618. trigger_type_btn = nil
  1619. trigger_mode_btn = nil
  1620. end
  1621. end
  1622. return tsb_wavein_page