Files
trail-mate/docs/sstv/SSTV.md
vicliuandGitHub 4c16f765db map (#9)
* feat: maps
2026-02-17 11:40:19 +08:00

14 KiB
Raw Permalink Blame History

你是资深嵌入式 GUI 工程师,请用 LVGL 9.xC/C++)实现一个 SSTV 接收页面(仅接收端 UI)。 屏幕分辨率:横屏 480(w) x 222(h)。 TopBar 高度:30px(必须严格)。 目标:按以下像素布局复刻 UI;整体尽量简洁;不画外框、不加多余容器效果;图片展示区域最大化;右侧显示状态文字 + 模式 + 音频电平;底部显示一条简洁的接收进度条(横向)。

============================================================

  1. 全局颜色与样式 token(固定,统一风格) ============================================================ 主色(Amber): #EBA341 (0xEBA341) 主色深(AmberDark): #C98118 背景(WarmBG): #F6E6C6 面板浅底(PanelBG): #FAF0D8 边线(Line): #E7C98F 文字主(Text): #6B4A1E 文字弱(TextDim): #8A6A3A 成功(Ok): #3E7D3E 警告(Warn): #B94A2C 灰(Gray): #6E6E6E

字体建议:

  • TopBar 标题:跟随系统主题默认字号
  • 状态文本:14px
  • 子状态/提示:14px
  • 小标签:12~14px

圆角:统一 8px(图片框也用 8px),不需要复杂阴影/浮雕。

============================================================ 2) 页面总体布局(像素级)

root480x222,背景 WarmBG。

分区: A) TopBarx=0, y=0, w=480, h=30 B) Mainx=0, y=30, w=480, h=192

Main 内部布局:

  • 左侧:ImageArea(3:2 容器)用于显示接收的图片
  • 右侧:InfoArea(文字信息 + 音频电平)
  • 底部:ProgressBar 横向进度条(位于右侧 InfoArea 底部,不覆盖图片)

(1) 图片容器(严格 3:2

  • img_boxx=8, y=0, w=288, h=192 说明:img_box 高度必须为 192(Main 全高),为满足 3:2,宽=192*1.5=288。 这样左侧图片最大化且比例正确。
  • img_box 样式:背景 PanelBG;边框 2px Line;圆角 8px;无额外内框。
  • 图片对象 img
    • 放在 img_box 内部,内容按“等比居中适配”:
      • 若收到的 SSTV 图为 3:2,直接填满;
      • 若不是,保持等比,留空用 PanelBG。

(2) 右侧信息区

  • info_areax=304, y=0, w=168, h=192 (因为 8px 左边距 + 288 图片 + 8px 间距 => 304 起) 宽度 480 - 304 - 8(右边距) = 168

(3) 进度条位置

  • prog_bgx=304, y=208, w=168, h=8(绝对坐标) (等价于 Main 内 y=178

============================================================ 3) TopBar30px,简洁)

TopBar 容器:与系统现有 UI 一致(复用 top_bar 组件) 元素:

  • btn_backx=8, y=4, w=22, h=22,显示返回图标,颜色 TextDim
  • title:居中对齐,文本 "SSTV RECEIVER",颜色 Text,字号 20
  • battery:右侧 x=420, y=6 显示电池图标(占位)+ 文本 "100%"x=446, y=5),颜色 TextDim

============================================================ 4) 右侧信息区(info_area

布局区域:info_area,位于图片右侧

(1) 状态/提示文本(label_state_sub

  • label_state_sub x=0, y=6, w=140(相对 info_area 文本示例:
    • "Listening for SSTV signal..."
    • "Decoding line: 120/240"
    • "Saved: /sstv/2026-02-09_001.bmp" 字体:14,颜色 TextDim

(2) 解析指标(新增 3 行) 位置:label_state_sub 与 label_mode 之间,约 80px 高度、140px 宽度

  • label_metric_syncx=0, y=34, w=140,文本 "SYNC: LOCK" / "SYNC: --"
  • label_metric_slantx=0, y=54, w=140,文本 "SLANT: --"
  • label_metric_levelx=0, y=74, w=140,文本 "LEVEL: 42%" 字体:14,颜色 TextDim

(3) 模式显示

  • label_mode x=0, y=106, w=140 文本示例:"MODE: Auto" / "MODE: Scottie 1" / "MODE: PD240" 字体:14,颜色 TextDim

(4) 就绪/状态提示

  • label_ready x=0, y=142, w=140 文本示例:
    • WAITING "SSTV RX READY"Text
    • RECEIVING "RECEIVING"Ok + Text
    • COMPLETE "COMPLETE"Ok
    • ERROR "ERROR"Warn 字体:14

============================================================ 5) 音频电平(右侧竖直电平表,必须)

位置:info_area 的最右侧贯穿中上区

  • meter_boxx=136, y=34, w=32, h=120(相对 info_area

样式:

  • 竖向 12 段,每段高 8px,段间距 2px
  • 底部段颜色 Ok(绿)
  • 中部段颜色 #C18B2C(黄棕)
  • 顶部段颜色 Warn(橙)
  • 未点亮段:Line 或 Gray(偏暗)
  • 外框:1~2px Line;背景透明或 PanelBG

实现:

  • 12 个小矩形 lv_obj 组成
  • 接口 ui_sstv_set_audio_level(float level_0_1)
    • level_0_1 映射点亮段数 n = round(level*12)
    • 从底部点亮 n 段

============================================================ 6) 底部进度条(简洁)

放在右侧 InfoArea 底部,不覆盖图片内容:

  • prog_bgx=304, y=208, w=168, h=8(绝对坐标)
  • 进度条背景:Line
  • 进度条填充:Amber
  • 圆角:2~4px
  • 接口 ui_sstv_set_progress(float p_0_1)

============================================================ 7) 状态机(至少支持 WAITING / RECEIVING / COMPLETE / ERROR

WAITING

  • img_box 显示占位
  • label_state_sub = "Listening for SSTV signal..."
  • label_ready = "SSTV RX READY"Text
  • progress = 0

RECEIVING

  • img 逐行刷新
  • label_state_sub = "Decoding line: x/xxx"
  • label_ready = "RECEIVING"Ok
  • progress 跟随解码进度

COMPLETE

  • img 显示最终图
  • label_state_sub = "Image received" 或 "Saved: ..."
  • label_ready = "COMPLETE"Ok
  • progress = 1.0

ERROR

  • label_state_sub = 错误描述
  • label_ready = "ERROR"Warn

必要接口:

  • void ui_sstv_set_state(enum State s)
  • void ui_sstv_set_mode(const char* mode_str)
  • void ui_sstv_set_audio_level(float level_0_1)
  • void ui_sstv_set_progress(float p_0_1)
  • void ui_sstv_set_image(const void* img_src_or_lv_img_dsc)

============================================================ 8) 交付要求

  • 提供 ui_sstv_create(lv_obj_t* parent) 返回 root 页面对象
  • 不使用任何外部 PNG/图标资源(返回箭头、电池可用字符或简单矢量绘制)
  • 严格 480x222TopBar=30img_box=288x1923:2
  • UI 必须足够简洁:禁止额外卡片、禁止厚重边框/阴影、禁止多余按钮(Mode/Clear/Save 不要)
  • 代码可编译,不要伪代码

============================================================ 9) Scottie 模式(协议说明)

VIS 码:

  • Scottie 160(十进制)
  • Scottie 256(十进制)
  • Scottie DX76(十进制)

颜色扫描顺序:绿、蓝、红(RGB) 亮度频率范围:15002300 Hz 行数:256Scottie 1/2 标准显示:320x256(包含 16 行头)

Scottie 1 时序:

  • 起始同步(仅首行):9.0 ms @ 1200 Hz
  • 分隔/porch1.5 ms @ 1500 Hz
  • 绿扫描:138.240 ms
  • 分隔/porch1.5 ms @ 1500 Hz
  • 蓝扫描:138.240 ms
  • 同步脉冲:9.0 ms @ 1200 Hz(位于蓝与红之间)
  • 同步 porch1.5 ms @ 1500 Hz
  • 红扫描:138.240 ms

首行之后,从“绿之前的分隔/porch”开始重复(不再有起始同步)。 注意:Scottie 的同步位于行中(蓝与红之间),不是行起始。 Scottie 2 时序差异:

  • 绿/蓝/红扫描:88.064 ms320 px 时 0.2752 ms/像素) Scottie DX 时序差异:
  • 绿/蓝/红扫描:345.6 ms320 px 时 1.0800 ms/像素) 其他时序(同步/porch)与 Scottie 1 相同。

============================================================ 10) VIS 头(JL Barber 提案)

来源:"Proposal for SSTV Mode Specifications"Dayton SSTV forum2000-05-20)。 该描述用于 VIS 解码对齐与奇偶校验的参考。

VIS / 校准头序列:

  • 300 ms @ 1900 Hzleader
  • 10 ms @ 1200 Hzbreak
  • 300 ms @ 1900 Hzleader
  • 30 ms @ 1200 HzVIS 起始位)
  • 7 个数据位,LSB 先行,每位 30 ms
    • 1100 Hz = “1”
    • 1300 Hz = “0”
  • 30 ms 奇偶校验位
    • 偶校验 = 1300 Hz
    • 奇校验 = 1100 Hz
  • 30 ms @ 1200 HzVIS 停止位)

注意:模式时序在 VIS 停止位之后立即开始。

============================================================ 11) Robot 72 彩色(模式说明)

VIS 码:12(十进制) 颜色模式:Y, R-Y, B-Y 扫描顺序:Y, R-Y, B-Y 行数:240

单行时序:

  • 同步脉冲:9.0 ms @ 1200 Hz
  • 同步 porch3.0 ms @ 1500 Hz
  • Y 扫描:138 ms
  • 分隔脉冲:4.5 ms @ 1500 Hz
  • Porch1.5 ms @ 1900 Hz
  • R-Y 扫描:69 ms
  • 分隔脉冲:4.5 ms @ 2300 Hz
  • Porch1.5 ms @ 1500 Hz
  • B-Y 扫描:69 ms

重复以上序列共 240 行。

============================================================ 12) Robot 36 彩色(模式说明)

VIS 码:8(十进制) 颜色模式:Y, R-Y, B-Y 扫描顺序:Y, R-Y(偶数行),Y, B-Y(奇数行) 行数:240

两行示例时序: 偶数行:

  • 同步脉冲:9.0 ms @ 1200 Hz
  • 同步 porch3.0 ms @ 1500 Hz
  • Y 扫描:88.0 ms
  • “偶数”分隔脉冲:4.5 ms @ 1500 Hz
  • Porch1.5 ms @ 1900 Hz
  • R-Y 扫描:44.0 ms

奇数行:

  • 同步脉冲:9.0 ms @ 1200 Hz
  • 同步 porch3.0 ms @ 1500 Hz
  • Y 扫描:88.0 ms
  • “奇数”分隔脉冲:4.5 ms @ 2300 Hz
  • Porch1.5 ms @ 1900 Hz
  • B-Y 扫描:44.0 ms

重复以上序列共 240 行。 注意:R-Y 在偶数行发送,B-Y 在奇数行发送。

============================================================ 13) Martin 模式(模式说明)

VIS 码:

  • Martin 144(十进制)
  • Martin 240(十进制)

颜色模式:RGB1500–2300 Hz) 扫描顺序:绿、蓝、红 行数:256

颜色扫描时间:

  • Martin 1146.432 ms320 px 时 0.4576 ms/像素)
  • Martin 273.216 ms320 px 时 0.2288 ms/像素)

每行时序:

  • 同步脉冲:4.862 ms @ 1200 Hz
  • 同步 porch0.572 ms @ 1500 Hz
  • 绿扫描
  • 分隔脉冲:0.572 ms @ 1500 Hz
  • 蓝扫描
  • 分隔脉冲:0.572 ms @ 1500 Hz
  • 红扫描
  • 分隔脉冲:0.572 ms @ 1500 Hz

重复以上序列共 256 行。

============================================================ 14) PD 模式(模式说明)

VIS 码:

  • PD5093(十进制)
  • PD9099(十进制)
  • PD12095(十进制)
  • PD16098(十进制)
  • PD18096(十进制)
  • PD24097(十进制)
  • PD29094(十进制)

颜色模式:Y, R-Y, B-Y 扫描顺序:Y(奇数行)、R-Y(两行平均)、B-Y(两行平均)、Y(偶数行) 同步脉冲:20.0 ms @ 1200 Hz Porch2.080 ms @ 1500 Hz

颜色扫描时间(Y、R-Y、B-Y):

  • PD5091.520 ms
  • PD90170.240 ms
  • PD120121.600 ms
  • PD160195.584 ms
  • PD180183.040 ms
  • PD240244.480 ms
  • PD290228.800 ms

标称分辨率(均包含 16 行头):

  • PD50320x256
  • PD90320x256
  • PD120640x496
  • PD160512x400
  • PD180640x496
  • PD240640x496
  • PD290800x616

注意:本接收端以 320 像素宽解码,并在垂直方向缩放到显示高度。

============================================================ 15) Pasokon “P” 模式(模式说明)

VIS 码:

  • P3113(十进制)
  • P5114(十进制)
  • P7115(十进制)

颜色模式:RGB1500–2300 Hz) 扫描顺序:红、绿、蓝 行数:496(包含 16 行头)

颜色扫描时间:

  • P3133.333 ms
  • P5200.000 ms
  • P7266.666 ms

同步/porch 时长:

  • P3:同步 5.208 msporch 1.042 ms
  • P5:同步 7.813 msporch 1.563 ms
  • P7:同步 10.417 msporch 2.083 ms

每行时序:

  • 同步脉冲
  • Porch
  • 红扫描
  • Porch
  • 绿扫描
  • Porch
  • 蓝扫描
  • Porch

重复以上序列共 496 行。 注意:本接收端以 320 像素宽解码,并在垂直方向缩放到显示高度。

============================================================ 16) PicoSSTV 解码算法概述

算法描述参考:

核心实现(PicoSSTV)基于以下流程:

  1. 音频采集与预处理

    • ADC 以 15000 Hz 采样
    • 直流偏置去除:dc = dc + (sample - dc) / 2
    • 使用去直流后的 sample 进入解码
  2. SSB/IQ 解调(decode_audio

    • 4 相移的 Fs/4 频移:audio -> (I,Q) 旋转
    • 半带滤波(half_band_filter2)低通去镜像
    • 再次旋转回基带得到 sample_i/sample_q
  3. 频率估计与平滑(decode_iq

    • CORDIC 计算相位
    • 频率 = last_phase - phase
    • 频率缩放:sample = (frequency * 15000) >> 16
    • IIR 平滑:smoothed = (smoothed*7 + sample) / 8
    • 夹紧到 1000..2500 Hz
  4. 行同步检测 + 模式识别(decode)

    • 同步条件:频率从 >=1300 跳到 <1300
    • confirm 累积 10 个低于 1300 的采样点判定有效 hsync
    • 计算 line_length = sample_number - last_hsync_sample
    • Auto 模式:与各模式 samples_per_line 做 +/-1% 匹配,取误差最小模式
    • 二次确认:下一条 sync 仍满足阈值才进入 decode_line
    • 注意:不依赖 VIS 头,仅靠行同步长度识别模式
  5. 像素映射与输出

    • sample_to_pixel 将 image_sample 映射到 (x,y,colour)
    • 亮度:1500..2300 Hz -> 0..255
    • 同一像素多次采样累积平均
    • 行结束或 y 达到 max_height 后结束图像,回到 detect_sync
  6. 自动斜率校正(Auto Slant

    • 每次有效 sync 后,用实际 line_length 更新 mean_samples_per_line
    • 通过 IIR 降低整图倾斜
  7. 颜色与模式渲染

    • Martin/ScottieRGB 顺序映射
    • Robot/PDY/Cr/Cb 转 RGB
    • BW:灰度直映射