更新一下进度,目前取得了显著的进展:我已经搞清楚了主控的真面目(并非完全确定,但有非常大把握),找到了 UART 接口,并下载到了对应的开发套件和工具链(SDK 和编译环境)
5. KL-908 的真面目
前面已经提到过,在网络上直接搜索 KL-908
没有任何有价值的结果,这意味着两种可能:
这颗 SoC 太过小众,是某厂商专门研发的专用芯片,且对外不公开资料;
这是别的什么芯片的换皮,即,将原来芯片的丝印磨掉之后,重新打标。这种手段在国内非常常见,其主要意图是防止破解。
第一种可能性其实非常小,因为这样做成本很高,小公司承担不起,第二种情况的可能性很大。
不过猜测归猜测,还是得拿出证据才行。一切的起点是,今天我在 flash.bin
里一通乱搜的时候,一个疑似 SDK 名称的东西出现了(ps:之前和群里大佬交流的时候,也提到过要注意这个):
hgSDK
想必就是开发这东西固件的 SDK 平台了,以它为关键词,在网上四处搜刮一下,我先是找到了 GitHub 上一个叫 T-Halow
的仓库里,有个目录是 hgSDK
:
Contribute to Xinyuan-LilyGO/T-Halow development by creating an account on GitHub.
这是一个 WiFi HaLow 的项目,使用了泰芯的 TXW830x
芯片 。WiFi HaLow 也即 IEEE 802.11ah,这是一个工作在 1GHz 频率以下 的、专为物联网设备设计的 WiFi 协议。和我这个采耳棒看起来好像没什么关系,毕竟它的 wifi 工作在 2.4GHz 频段。
继续搜索 hgSDK
关键词,经过一上午的翻找后,真正破局的是这个帖子的出现:Mini 1080p wifi camera from Aliexpress, how to use without app (FtyCamPro)?
该帖的楼主在全球速卖通上买了个便宜的 wifi 摄像头,拆开看发现是 BK7252 主控。不过最关键的是 6 楼有人给出了一个很类似的摄像头, 但是芯片是泰芯 TXW817-810
。 层主提供了一张非常高清的近照:
这张图中可以看清楚主控的一些引脚和外围电路之间的连接。有几个关键的引脚值得注意:
图中主控 48 脚(照片最下面那一排引脚的最右侧那个)经历了一个简单的 LC 射频前端电路后连接到了 PCB 上的天线;
45,46,47 脚被连接在一起,然后经过一个电容连接到 GND;
43,44 脚似乎是接到了 40MHz 外部晶振(右下银白色的那个);
1-24 脚大多是细长的并列连线,推测为数字信号连线,这意味着该主控的 GPIO 和大部分 peripherals 可能在这些引脚上引出。
对比这些特征,和我这个采耳棒上的 KL-908
与外围电路的连接方式完全一致 。由此怀疑 KL-908 就是 TXW817-810
,或其同系列相似型号。
另一个非常激动人心的事情是,该帖子中层主还成功地找到了 UART 接口,并从 UART 读到了它的 boot log,我复制一部分过来:
<... 上面省略>
[0]00 00 00 00 00 10 e4 00
[0]f0 3c 0f
[0]validity: 1678e00d
** hgSDK-v2.5.1.7-26745, app-0, build time:Jan 18 2024 21:55:13 **
** libcore v2.5.1.7-26745, build time:Dec 18 2023 11:05:53
** libnetutils v2.5.1.7-26745, build time:Dec 18 2023 11:06:10
** libcommon v2.5.1.7-26745, build time:Dec 18 2023 11:05:58
<下面省略...>
可以看到,其中明确地出现了 hgSDK
字样,且格式和我们在固件里找到的完全一致,更加确定了这个推测,即,KL-908 很可能就是 TXW817-810 .
6. 找到 UART 并读出内容
经过一些观察和尝试,发现 UART 接口在板子上一个非常隐蔽的位置:
在画圈处,有一个很小的空焊盘,直接连接到芯片的 25 脚,除此之外没有和任何其它东西相连,并且甚至还写了个 T
标记在旁边。。。经过一些测试,这里确实就是 UART 的 TX 接口 ,至于 RX 接口我并没有找到,而且应该没有什么用,所以我就不关心它了。
接下来要确定 UART 的波特率,逻辑分析仪或示波器都可以做到这一点,我就用示波器了。把示波器挂在 TX 和 GND 之间,然后寻找一个持续时间最小的高电平来观察(除了空闲电平外,所有的高电平持续时间都是这个最小时间的整数倍,所以这个最小的高电平还是很好找的) :
如图,用 Measure 或 Cursor 功能测量一下这个高电平的持续时间,这里是 1.07us,考虑误差,与之对应的可能有两个常见的波特率,1000000 (1us 显性电平)或 921600(1.085us 显性电平) ,两个都试一下,看看哪个能得到有意义的输出就行了。
测试之后发现 921600 可以得到有意义的输出(更准确地说,它采用 UART 921600 8N1,即921600 波特率,8 位数据位,无奇偶校验,1 位停止位 ),启动过程中 UART 输出如下:
[0]40 00 57 00 a3 44 12 a0
[0]28 f2 00 00 00 00 00 00
[0]00 00 00 00 00 00 00 00
[0]47 87 81 16 88 35 66 a6
[0]8a a5 89 88 9e 57 00 00
[0]80 00 bc 02 a0 ca 00 00
[0]00 1d 00 00 0e 0a 00 00
[0]00 00 00 00 09 30 03 00
[0]00 00 00 00 08 84 40 08
[0]84 40 08 84 40 08 84 03
[0]08 3f 1e e8 81 5e f8 c4
[0]3f f8 83 0f f8 f5 fe f6
[0]ff 00 f8 f7 0f 00 ee fe
[0]ee 00 00 f0 ea 00 00 1d
[0]00 03 b2 00 00 00 00 07
[0]00 00 00 00 00 73 0a 00
[0]78 50 00
[0]cpu clk: 120
[0]flash clk: 80
[0]psram clk: 0
[0]validity: 1579e00d
[0][OTA_MSG] OTA_NUM:0 ota_version:31060 run_addr:0
** hgSDK-v2.5.0.7-31060, app-0, build time:Oct 25 2024 15:55:12 **
** libcore v2.5.0.7-31060, build time:Oct 21 2024 15:49:37
** libnetutils v2.5.0.7-31060, build time:Oct 21 2024 15:49:52
** libcommon v2.5.0.7-31060, build time:Oct 21 2024 15:49:43
** libosal v2.5.0.7-31060, build time:Oct 21 2024 15:49:36
** libatcmd v2.5.0.7-31060, build time:Oct 21 2024 15:49:43
** liblmac v2.5.0.7-31060, build time:Oct 21 2024 15:50:08
** libwifi v2.5.0.7-31060, build time:Oct 21 2024 15:50:18
------------------------------------------------------------------
[0] ------- system restart fault -----------
[0] ---------------------------------------
[1]freemem:160596
[1]custom_mem_init:2000d258
[2]custom mem sram:61440
[2]skbpool init, total:45656 (0x200389a8~0x20043c00), max per:80%
[3]syscfg_read OK!
[3]old cfg_ver:259
[6]lmac rx info size:36
[6]GAP0 : 200345a8
[6]GAP1 : 200389a0
[6]lmac rx buff:200345b0, size:17392, hw rx buff size:11368, ampdu:7, max subfrm:3
[7]lmac priv: 2001d268
[8]lmac tx : 2001d628
[8]lmac rx : 2001e7f4
[8]lmac ble rx: 00000000
[9]pack:7, bios_id:3
[9]use AMPM DPD!
[9]verf:0x6, ibpt:0xa, ibct:0xa, iref:0x6
[10]verfvco_trim:0x8, verfcp_trim:0x6, verfdiv_trim:0x5
[10]verfdsm_trim:0x4, verfvcc25_trim:0x1
[11]da cap:7, da gain:1
[14]txdcoc from:1, i:14, q:10
[14]tx imb from:1, pm:51, gm:9
[15]rx dcoc from:1
[15]g:0, ana:2048, i:2, q:0
[15]g:1, ana:2112, i:4, q:2
[16]g:2, ana:2112, i:4, q:2
[16]g:3, ana:2112, i:8, q:6
[16]g:4, ana:2112, i:7, q:7
[17]g:5, ana:2112, i:6, q:6
[17]g:6, ana:2112, i:6, q:6
[17]g:7, ana:2112, i:3, q:8
[18]rx imb from:1
[18]g:0, 8174, 4077
[18]g:1, 8190, 4086
[19]g:2, 8174, 4078
[19]g:3, 0, 4087
[19]g:4, 0, 4088
[19]g:5, 8176, 4080
[20]g:6, 8170, 4079
[20]g:7, 0, 4088
[20]time offset:0, 29
[20]!!! rf pack err !!!
[21]lmac test: 2001efa0
[21]lmac_bgn_lo_freq_set: 2432
[23]set rts_threshold =2304
[23]lmac set mac0 addr:46:87:81:35:88:d8
[24]*** open ADC success!
[24]*** add success: ADC channel cnt = 1, name:257
[25]*** add success: ADC channel cnt = 2, name:258
[25]*** add success: ADC channel cnt = 3, name:262
[26]*** delete success: ADC channel cnt = 2
[29]lmac_bgn_lo_freq_set: 2412
[31]lmac_bgn_lo_freq_set: 2412
[32]set rts_threshold =1600
[32]set ac= 0 aifs= 2 cw_min= 15 cwmax= 1023 txop= 79
[33]set ac= 1 aifs= 6 cw_min= 15 cwmax= 1023 txop= 79
[34]set ac= 2 aifs= 1 cw_min= 7 cwmax= 15 txop= 128
[34]set ac= 3 aifs= 1 cw_min= 3 cwmax= 7 txop= 65
[35]set ac= 0 aifs= 2 cw_min= 15 cwmax= 1023 txop= 79
[36]set ac= 1 aifs= 6 cw_min= 15 cwmax= 1023 txop= 79
[36]set ac= 2 aifs= 1 cw_min= 7 cwmax= 15 txop= 128
[37]set ac= 3 aifs= 1 cw_min= 3 cwmax= 7 txop= 65
[38]lmac_bgn_lo_freq_set: 2437
[39]inteface1: start scanning ...
[40]vif1 state WPA_DISCONNECTED -> WPA_SCANNING
[41]lmac dbg!!!mac addr err:00:00:00:00:00:00
[41]Func:lmac_bgn_tx_check Line:784 LR=0x1802b0c4
[240]lmac dbg!!!mac addr err:00:00:00:00:00:00
[240]Func:lmac_bgn_tx_check Line:784 LR=0x1802b0c4
[2117]lmac set mac0 addr:46:87:81:35:88:d8
[2118]lmac_bgn_lo_freq_set: 2412
[2120]lmac set mac0 addr:46:87:81:35:88:d8
[2120]lmac_bgn_lo_freq_set: 2412
[2122]ieee80211_ap_ioctl:164::set channel 1
[2122]set ac= 0 aifs= 1 cw_min= 1 cwmax= 3 txop= 0
[2123]set ac= 1 aifs= 1 cw_min= 1 cwmax= 3 txop= 0
[2123]set ac= 2 aifs= 1 cw_min= 1 cwmax= 3 txop= 0
[2124]set ac= 3 aifs= 1 cw_min= 1 cwmax= 3 txop= 0
[2125]vif2 state WPA_DISCONNECTED -> WPA_COMPLETED
[2127]add w0 interface!
JPG start
[2128]csi_test start,iic init
[2129]iic init finish,sensor reset & set sensor clk into 6M
hgdvp_set_baudrate:clock:480000000
[2133]set sensor finish ,Auto Check sensor id
[2133]SID: ff, a0, 42, 43,0
[2134]SID: ff, bb, 66, 67,f0
[2135]SID: ff, 10, 42, 43,f1
[2136]SID: ff, 9d, 42, 43,f0
[2136]preset table num:2
[2137]SID: ff, c0, 62, 63,0
[2138]SID: 20, 3a, dc, dd,fc
[2138]SID: 20, 37, dc, dd,fc
[2139]SID: 20, 38, dc, dd,fc
[2140]SID: a6, a6, dc, dd,fd
[2140]id =a6 num:8
[2140]Auto Check sensor id finish
[2141]mclk:24000000MHz
hgdvp_set_baudrate:clock:480000000
[2141]init:1804f340 u8Addrbytnum:1,u8Databytnum:1
[2142]SENSER....init
[2182]init table num:308
[2183]SENSR ident ok:480*480
[2183]csi init start --
[2183]csi set size ====>480*480
[2184]csi dvp_size_set
[2184]csi IRQ init
[2184]dvpirq_register:1 1801a4e0 1801a4e0
[2185]dvpirq_register:0 1801a4cc 1801a4cc
[2185]vppirq_register:0 1801a2fc 1801a2fc
[2186]vppirq_register:1 1801a640 1801a640
[2186]vppirq_register:2 1801a2f8 1801a2f8
[2187]vppirq_register:3 1801a49c 1801a49c
[2187]vppirq_register:4 1801a4b0 1801a4b0
[2188]vppirq_register:5 1801a2e8 1801a2e8
[2188]vppirq_register:6 1801a2d8 1801a2d8
[2189]vppirq_register:7 1801a2c8 1801a2c8
[2189]csi IRQ init finish,start get data
eloop_init:287::start
user_eloop_run:309::run
[2193]dns sock :2
[test] init tcp server: port: 5007
[2194]ota num:0 version:31060
g_sensor_init start,iic init:200004a0
init g_sensor,check id
SID: ff, 13, 4e, 4f,1
SID: 26, 26, 32, 33,70
id =26 num:1
init table num:22
gsensor_ok
adc_open_ok
[2202]*** add success: ADC channel cnt = 3, name:2
adc_add_channel_ok
> udp_user_data_init
udp port:7099
enter usr_udp_create_server_test
udp server ok:4
port:7070 fd:5
[2207]set_video_track:364
[2207]set_video_track source->track[t]:0 rtp:200290B0
[2208]set_video_track:364
[2208]set_video_track source->track[t]:0 rtp:200296D4
[2209]no this event(20005)...
[2209]scan down.......
前面的方括号里的看起来应该是时间戳,代表了从启动开始的毫秒数。启动完成后,它开始周期性地输出这些内容(此时没有手机连接):
vol_f:3652
vol_f:3652
vol_f:3650
vol_f:3650
[3209]custom mem sram:61440
[3209]freemem:42824
vol_f:3650
vol_f:3650
vol_f:3650
vol_f:3650
[4209]custom mem sram:61440
[4209]freemem:42824
vol_f:3648
vol_f:3648
vol_f:3648
--------------------
local:46:87:81:35:88:d8
!!! chip pack err !!!
bios:3, pack:7
pwr idx: 0
chip-temperature: 36
freq:2412, bg_rssi:-83
cca: -70, -60, -62
tx: txq:0, ps:0, tx_stat_q:0,
tx dma:1, total tx:0, retry:0, tx lost:0, tx err:0
rx: frms:41, data:0
throughput: tx: 0 bps, rx: 0 bps
max gain:7
--------------------
上面这段内容被不断重复,(那个 vol_f
的值是不断变化的,还有一些诸如温度和 RSSI(wifi 信号强度)也是在变化的),当有手机连接上它的热点时,输出开始有变化:
[49557]lmac_bgn_add_sta: if:1, aid1, addr:32:ec:a9:e6:9e:fb[49558]rc_init: type= 2 mcs_mask= 0x3cc
[49558]inteface2: sta 32:ec:a9:e6:9e:fb connected
[49559]user_sta_add:32 ec a9 e6 9e fb
[49693]send DHCP_OFFER ...
[49694]Next IP: 192.168.1.101
[49694]Assign IP 192.168.1.100 for 32:ec:a9:e6:9e:fb, flags=0 (next:192.168.1.101)
vol_f:3618
[49708]send DHCP_ACK ...
[49709]Assign IP 192.168.1.100 for 32:ec:a9:e6:9e:fb, flags=0 (next:192.168.1.101)
[49711]IP Pool:
[49712] ip:192.168.1.100 - 32:ec:a9:e6:9e:fb
这印证我们之前关于它内置 DHCP server 的猜测。
接下来在手机上打开 YW tool,开始查看摄像头,输出又有变化:
do_accept 477
do_accept c:2002A124
do_read:372
===========OPTIONS=============
RTSP/1.0 200 OK
CSeq: 1
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE
do_read:372
===========DESCRIBE=============
[53363]live_get_sdp:88 path:/webcam
[53363]live_get_sdp:95
[53364]À source->track[t]:200290B0 rtp:200292A8
[53364]live_get_sdp:119
RTSP/1.0 200 OK
CSeq: 2
Content-Base: rtsp://192.168.1.1:7070/webcam/
Content-Type: application/sdp
Content-Length: 122
rtsp_teardown:147
rtsp_release_event:132
del_session session:2002A794
do_read:372
===========SETUP=============
[53381]jpeg_stream_init:713
[53382]opcode_func:270
[53383]src:2002A890
[53383]src open_ref:1
RTSP/1.0 200 OK
CSeq: 3
Transport: RTP/AVP;unicast;client_port=20318-20319;server_port=53796-53797
Session: 82838485868788898A8B8C8D8E8F90
[53392]rtsp_live_thread:23
do_read:372
===========PLAY=============
RTSP/1.0 200 OK
CSeq: 4
Session: 82838485868788898A8B8C8D8E8F90
可以看到是在处理 RTSP 协议。
以上是在 UART 上观察的全部内容了。 UART 内容和上文提到的那个帖子里的 UART 内容几乎一致,于是进一步肯定了这块主控就是 TXW817 的猜测。
7. Dive into TXW817-810
这个芯片的 datasheet 可以在网上找到,也可以看泰芯官网的介绍 。
它是一个集成了很多常见外设的物联网 SoC,还带有 WiFi, BLE,以及 mjpeg 硬件编解码单元,其核心是一个 国产自研 CSKY 指令集架构的 CK803 CPU :
CK803 是一颗具有 3 级 pipeline,32KB cache 的 32 位 RISC CPU 核心:
我之前对这个 CSKY 架构是闻所未闻的,不过据网上介绍,其出货量相当大,想必应该是已经渗透进我们生活中的各种产品了。
8. SDK 和 Toolchain
据官网介绍,该芯片要使用 CDK 开发环境(也是一个自研 IDE,用 wxWidgets 写的,仅支持 windows 平台),搭配官方的 SDK. 感兴趣的读者可以去官网下载 linux 的 toolchain 来研究(基于 gcc):csky-elf-noneabiv2-tools-x86_64-newlib-20210423.tar.gz
这次更新的进展主要是硬件方面的。目前我正在根据 SDK 的代码来进一步研究,如果有新的进展会保持更新。
我目前搜集到的资料已经上传到 github,包含 flash 全量 dump,txw817 的 datasheet,还有官方的 software design doc.
RYEVi 可视化采耳棒(主控丝印 KL-908)固件逆向实验