固件 A15:启动顺序 + 降级矩阵(bringup.{h,c},已上板)
- 启动序列从 app_main.c 拆进 main/bringup.{h,c},宿主机可测:
bringup_devices()(§10.9 第 1~4 步)→ 起 t_safety → bringup_power_restore()(第 5~6 步)
- 六片 INA226 写 Config/Calibration(之前没做,电流恒 0);输入侧 0x43 登记对调接
- 按「意图」逐路上电、错开 100 ms、每路等 PG 500 ms,等不到关回去并记 LOG_EV_PG_TIMEOUT(17)
- 意图只由 power 命令改(cmd_env_t.intent → NVS phonerail/rail_want)
- §10.10 逐行降级:INA/DAC/PCA9555/mux/PRSNT#/CH224A;mux 失联时不碰主干
- BOOT 事件 arg = 复位原因;HUB_RST# 仍只在上电复位时脉冲
- rail_volt_init() 一片失败不再放弃另一片;CH224A 主干 / 通道 5 两处都找
- sim:sim_gpio_rise_us / sim_gpio_set_hook,sim_gpio_drive 可在配置前调
- test_bringup.c 24 例 + test_cmd 意图 1 例,共 425 例全绿;版本 0.1.0-a15
- rack:事件表加 17 PG_TIMEOUT(已部署)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -0,0 +1,410 @@
|
||||
/* 启动顺序 + 降级矩阵。契约与 §10.10 各行的落点见 bringup.h。 */
|
||||
#include "bringup.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "board_pins.h"
|
||||
#include "ch224a.h"
|
||||
#include "dac63204.h"
|
||||
#include "evlog.h"
|
||||
#include "hal_gpio.h"
|
||||
#include "hal_i2c.h"
|
||||
#include "hal_lock.h"
|
||||
#include "hal_time.h"
|
||||
#include "i2cbus.h"
|
||||
#include "ina226.h"
|
||||
#include "pca9555.h"
|
||||
#include "rail.h"
|
||||
#include "rail_cfg.h"
|
||||
#include "slot.h"
|
||||
#include "tca9548a.h"
|
||||
|
||||
/* 启动期拿锁等多久。此刻只有巡检(第二段)在和我们抢,它一次最多持锁 ~2 ms。 */
|
||||
#define BRINGUP_LOCK_MS SLOT_LOCK_TIMEOUT_MS
|
||||
|
||||
static uint8_t bit_of(int rail) { return (uint8_t)(1u << (rail - 1)); }
|
||||
|
||||
static void lost(int rail, uint8_t addr, hal_err_t err)
|
||||
{
|
||||
/* arg = 地址(evlog.h 的约定),current_ua 顺手带上 HAL 错误码 ——
|
||||
NAK(不在)与 BUS(在但 ID 不对 = 贴错件)是两种完全不同的现场。 */
|
||||
evlog_put((uint8_t)rail, LOG_EV_I2C_LOST, addr, 0, (int32_t)err);
|
||||
}
|
||||
|
||||
/* ---- 一次 xact 的正文们 -------------------------------------------------- */
|
||||
|
||||
static hal_err_t nop_fn(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
return HAL_OK; /* 选通道本身就是探测:选得中 = mux 在 */
|
||||
}
|
||||
|
||||
static hal_err_t ina_up_fn(void *arg)
|
||||
{
|
||||
const uint8_t addr = *(const uint8_t *)arg;
|
||||
hal_err_t err = ina226_probe(addr);
|
||||
return (err == HAL_OK) ? ina226_init(addr) : err;
|
||||
}
|
||||
|
||||
static hal_err_t dac_up_fn(void *arg)
|
||||
{
|
||||
return rail_volt_init_one(*(const uint8_t *)arg);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint16_t mv[PHONERAIL_RAIL_COUNT];
|
||||
} dac_peek_t;
|
||||
|
||||
static hal_err_t dac_peek_fn(void *arg)
|
||||
{
|
||||
dac_peek_t *p = (dac_peek_t *)arg;
|
||||
for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) {
|
||||
int mv = 0;
|
||||
p->mv[rail - 1] = (rail_get_mv(rail, &mv) == HAL_OK) ? (uint16_t)mv : 0u;
|
||||
}
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
static hal_err_t pd_fn(void *arg)
|
||||
{
|
||||
return ch224a_read_max_ma(CH224A_ADDR_DEFAULT, (uint32_t *)arg);
|
||||
}
|
||||
|
||||
/* ---- 第一段 -------------------------------------------------------------- */
|
||||
|
||||
/* USB2517I 的复位脉冲 —— **整个固件里唯一碰 `HUB_RST#` 的地方,而且只在启动调一次**
|
||||
(A15 从 app_main.c 搬过来的,理由原样保留)。
|
||||
|
||||
低有效(板上 R716 上拉到 +3V3_HUB),给 1 ms 足够:手册要的是几十微秒量级。
|
||||
|
||||
⛔⛔ **运行期一个字都不许再写它**(R2 D13 代价 2)。ESP32 自己的
|
||||
USB-Serial-JTAG 就挂在这个 Hub 的第 6 个下行口上,所以复位 Hub =
|
||||
**自己把自己的控制台拔了**,而且下一次 `idf.py flash` 也进不来
|
||||
—— 到那时候唯一的退路是 J33 那个 5P 应急串口(UART0,IO43/IO44),
|
||||
得拆机接线。写一行 "Hub 卡了就复位一下" 的自愈代码,代价是整机变砖。
|
||||
|
||||
⛔ **只在上电复位(`ESP_RST_POWERON`)时脉冲**(2026-09-27 上板改)。
|
||||
ESP32 的每一次重启都算启动:esptool 经 USB 复位芯片、崩溃 / 看门狗重启、
|
||||
`esp_restart()` —— 原来每一次都把 Hub 复位、把自己的 COM 口拔掉,实测
|
||||
`esptool --before usb_reset` 连三次全断(`ClearCommError PermissionError 13`)。
|
||||
上电复位时 Hub 自己也刚上电,脉冲没有代价;J33 的 EN 脚复位在 S3 上也报 POWERON,
|
||||
应急路径不受影响。其余原因**连配置都不做**(配成输出那一刻就是输出 0 = 一次复位),
|
||||
它仍是复位态的高阻,靠 R716 拉高。
|
||||
|
||||
失败**不 abort**:Hub 没起来只影响调试与手机的数据口,五路供电照常(§10.2)。 */
|
||||
static void hub_pulse(void)
|
||||
{
|
||||
if (hal_gpio_config(BOARD_PIN_HUB_RST_N, HAL_GPIO_OUTPUT) != HAL_OK) {
|
||||
return;
|
||||
}
|
||||
(void)hal_gpio_write(BOARD_PIN_HUB_RST_N, 0); /* 低 = 复位 */
|
||||
hal_time_delay_ms(1);
|
||||
(void)hal_gpio_write(BOARD_PIN_HUB_RST_N, 1); /* 放开,之后再也不动 */
|
||||
}
|
||||
|
||||
/* mux:`i2cbus_init()` 认不到 ⇒ 按 §5.8 先脉冲一次 `MUX_RST#` 再判。 */
|
||||
static bool mux_up(bringup_report_t *r)
|
||||
{
|
||||
if (i2cbus_init() == HAL_OK) {
|
||||
return true;
|
||||
}
|
||||
(void)i2cbus_recover(); /* 影子作废 ⇒ 下面那次 xact 一定真的发选通字节 */
|
||||
if (i2cbus_xact(I2CBUS_CH_TRUNK, BRINGUP_LOCK_MS, nop_fn, NULL) == HAL_OK) {
|
||||
return true;
|
||||
}
|
||||
r->deg |= BRINGUP_DEG_MUX;
|
||||
evlog_put(0, LOG_EV_MUX_LOST, 0, 0, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void dac_up(const bringup_in_t *in, bringup_report_t *r)
|
||||
{
|
||||
/* §10.9 第 3 步:读回 NVM 默认值与期望比对。**只在上电复位时有意义** ——
|
||||
热重启时 DAC 没断过电,里面是上一条 set_voltage 设的值,不是 NVM 默认。
|
||||
它要证明的是「DAC 不应答时输出会停在 3.90 V」这条降级前提还成立。 */
|
||||
if (in->power_on_reset) {
|
||||
dac_peek_t p;
|
||||
memset(&p, 0, sizeof(p));
|
||||
(void)i2cbus_xact(I2CBUS_CH_TRUNK, BRINGUP_LOCK_MS, dac_peek_fn, &p);
|
||||
for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) {
|
||||
r->dac_nvm_mv[rail - 1] = p.mv[rail - 1];
|
||||
/* 读不到(0)归「不应答」那一行管,这里只抓「读到了但不对」。
|
||||
容差一个码以内:码 ↔ mV 的换算本身有 ±1 mV 的取整。 */
|
||||
const int d = (int)p.mv[rail - 1] - RAIL_MV_SAFE;
|
||||
if (p.mv[rail - 1] != 0 && (d > 1 || d < -1)) {
|
||||
r->deg |= BRINGUP_DEG_DAC_NVM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t deg_bit[DAC63204_COUNT] = { BRINGUP_DEG_DAC_U6, BRINGUP_DEG_DAC_U7 };
|
||||
_Static_assert(DAC63204_COUNT == 2, "deg_bit 跟着改");
|
||||
bool any_fail = false;
|
||||
for (int i = 0; i < DAC63204_COUNT; i++) {
|
||||
uint8_t addr = dac63204_all_addr[i];
|
||||
const hal_err_t err = i2cbus_xact(I2CBUS_CH_TRUNK, BRINGUP_LOCK_MS, dac_up_fn, &addr);
|
||||
if (err != HAL_OK) {
|
||||
r->deg |= deg_bit[i];
|
||||
lost(0, addr, err);
|
||||
any_fail = true;
|
||||
}
|
||||
}
|
||||
/* §10.10:DAC 不应答 **不关输出** —— 输出停在 NVM 默认 3.90 V,是安全值。
|
||||
影子也得说这句实话,否则判据拿一个「上次设过的值」去比,会把 3.90 判成偏离。 */
|
||||
if (any_fail) {
|
||||
rail_setpoint_reset();
|
||||
}
|
||||
}
|
||||
|
||||
static void pd_up(bringup_report_t *r)
|
||||
{
|
||||
/* ⚠️ CH224A 在哪条支路上,设计文档与实物**不一致**:驱动头写的是 mux 通道 5,
|
||||
而 2026-09-27 板 B 实测它在**主干**应答(0x22/0x23,PROGRESS 顶部)。
|
||||
两处都试:先主干(实测),不应答再试通道 5(设计)。
|
||||
选到通道 5 时主干照样看得见,所以这不会读到别的东西。 */
|
||||
uint32_t ma = 0;
|
||||
hal_err_t err = i2cbus_xact(I2CBUS_CH_TRUNK, BRINGUP_LOCK_MS, pd_fn, &ma);
|
||||
if (err != HAL_OK) {
|
||||
err = i2cbus_xact(TCA9548A_CH_PD, BRINGUP_LOCK_MS, pd_fn, &ma);
|
||||
}
|
||||
|
||||
uint8_t arg = 0;
|
||||
if (err != HAL_OK || ma == 0) {
|
||||
r->deg |= BRINGUP_DEG_PD;
|
||||
r->pd_ma = 0;
|
||||
r->pd_limit_mw = ch224a_power_limit_mw(BRINGUP_PD_FALLBACK_MA);
|
||||
arg = 1; /* 1 = 按保守值 */
|
||||
if (err != HAL_OK) {
|
||||
lost(0, CH224A_ADDR_DEFAULT, err);
|
||||
}
|
||||
} else {
|
||||
r->pd_ma = ma;
|
||||
r->pd_limit_mw = ch224a_power_limit_mw(ma);
|
||||
if (ma < BRINGUP_PD_FALLBACK_MA) {
|
||||
r->deg |= BRINGUP_DEG_PD_LOW;
|
||||
}
|
||||
}
|
||||
/* 不管读没读到都记一条:「这次上电按多少瓦跑」是排查降载的第一个问题。
|
||||
⚠️ 本包只**定**上限;逼近上限时按优先级降载(§8.3)还没人做(HANDOFF)。 */
|
||||
evlog_put(0, LOG_EV_PD_LIMIT, arg, (int32_t)(r->pd_limit_mw / 100u), (int32_t)ma);
|
||||
}
|
||||
|
||||
hal_err_t bringup_devices(const bringup_in_t *in, bringup_report_t *r)
|
||||
{
|
||||
assert(in != NULL && r != NULL);
|
||||
memset(r, 0, sizeof(*r));
|
||||
|
||||
/* ① 五根 `EFUSE_EN` 配成输出并拉低。**先于一切外设**:DAC / eFuse 一上电就有
|
||||
输出,这五根线这时必须已经确定是低的。VBUS 此刻靠硬件关着(PCA9555 复位后
|
||||
全是输入 + R701 下拉),真正「固件说了算」要等下面的 `slot_init()`。 */
|
||||
hal_err_t err = rail_en_init();
|
||||
if (err != HAL_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Hub 越早复位越好:它会让 USB 重新枚举,期间日志是丢的。 */
|
||||
if (in->power_on_reset) {
|
||||
hub_pulse();
|
||||
}
|
||||
|
||||
/* 锁必须早于任何一个用总线的人(R2 之后全系统只剩这一把)。 */
|
||||
(void)hal_lock_init();
|
||||
const hal_i2c_cfg_t i2c = {
|
||||
.sda_gpio = BOARD_PIN_I2C_SDA,
|
||||
.scl_gpio = BOARD_PIN_I2C_SCL,
|
||||
.freq_hz = 400000,
|
||||
};
|
||||
err = hal_i2c_init(&i2c);
|
||||
if (err != HAL_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const bool mux_ok = mux_up(r);
|
||||
|
||||
/* `PRSNT#`:失败 = 引脚号非法 = 固件写错了,而且降级方向是不安全的那一侧
|
||||
(`slot_present()` 读不到时返回「在位」⇒ 空槽也会被允许上电)。 */
|
||||
err = slot_prsnt_init();
|
||||
if (err != HAL_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ⭐⭐ 底板输入侧 U13(0x43)的 IN+/IN− **在板上是对调接的**(计划 §5.9)。
|
||||
漏了这一行,正常供电时它读回来的电流是负的,被当成反灌 ——
|
||||
`test_bringup.c` 的第一条用例就是它。纯软件状态,不碰总线。 */
|
||||
ina226_set_reversed(INA226_ADDR_INPUT, true);
|
||||
|
||||
/* ② 主干:两片 DAC、输入侧 INA226、CH224A。
|
||||
⚠️ **mux 失联时主干也够不着**:`i2cbus_xact(TRUNK)` 要先给 mux 写「全关」,
|
||||
那一步失败 fn 就不会被调(i2cbus.h 规矩 2)。物理上主干器件还在,但这一层
|
||||
没有「绕过 mux」的路 —— 也不该有,否则通道影子就不可信了。
|
||||
这时五路反正一路都不开(§5.8),所以不去试、不刷三条误导性的 I2C_LOST,
|
||||
只把状态说成实话:DAC 停在 NVM 默认、功率按保守值。 */
|
||||
if (mux_ok) {
|
||||
dac_up(in, r);
|
||||
uint8_t addr = INA226_ADDR_INPUT;
|
||||
const hal_err_t e = i2cbus_xact(I2CBUS_CH_TRUNK, BRINGUP_LOCK_MS, ina_up_fn, &addr);
|
||||
if (e != HAL_OK) {
|
||||
r->deg |= BRINGUP_DEG_INPUT_INA;
|
||||
lost(0, addr, e);
|
||||
}
|
||||
pd_up(r);
|
||||
} else {
|
||||
rail_setpoint_reset();
|
||||
r->pd_limit_mw = ch224a_power_limit_mw(BRINGUP_PD_FALLBACK_MA);
|
||||
}
|
||||
|
||||
/* ③ 五片刀片。空槽不去碰(只会白等 NAK);mux 失联时一路也够不着。 */
|
||||
for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) {
|
||||
if (!slot_present(rail)) {
|
||||
r->empty |= bit_of(rail);
|
||||
continue;
|
||||
}
|
||||
if (!mux_ok) {
|
||||
continue; /* 整板级已经记过 MUX_LOST,不再逐路刷十条 I2C_LOST */
|
||||
}
|
||||
/* PCA9555:驱动保证「输出锁存器先清零、方向最后改」(计划 §5.3)。
|
||||
这一步之后 VBUS 才真的由固件说了算。 */
|
||||
hal_err_t e = slot_init(rail);
|
||||
if (e != HAL_OK) {
|
||||
r->io_lost |= bit_of(rail);
|
||||
lost(rail, PCA9555_ADDR, e);
|
||||
}
|
||||
uint8_t addr = rail_cfg(rail)->ina_addr;
|
||||
e = i2cbus_xact(slot_mux_ch(rail), BRINGUP_LOCK_MS, ina_up_fn, &addr);
|
||||
if (e != HAL_OK) {
|
||||
r->blind |= bit_of(rail);
|
||||
lost(rail, addr, e);
|
||||
}
|
||||
}
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/* ---- 第二段 -------------------------------------------------------------- */
|
||||
|
||||
typedef struct {
|
||||
int rail;
|
||||
pca9555_in_t in;
|
||||
ina226_vi_t vi;
|
||||
} probe_t;
|
||||
|
||||
static hal_err_t read_io_fn(void *arg)
|
||||
{
|
||||
probe_t *p = (probe_t *)arg;
|
||||
return slot_read_inputs_locked(p->rail, &p->in);
|
||||
}
|
||||
|
||||
static hal_err_t read_vi_fn(void *arg)
|
||||
{
|
||||
probe_t *p = (probe_t *)arg;
|
||||
return ina226_read_vi(rail_cfg(p->rail)->ina_addr, &p->vi);
|
||||
}
|
||||
|
||||
typedef enum { PG_WAIT, PG_OK, PG_BLIND } pg_t;
|
||||
|
||||
/* 这一路的电源好了没有。优先看 PCA9555 的 PGOOD;读不到就退到 INA226 的电压
|
||||
(§10.10 PCA9555 那一行「改用 INA226 的电压判据兜底」);两样都读不到 = 看不见。 */
|
||||
static pg_t pg_of(int rail, const bringup_report_t *r, uint8_t *arg)
|
||||
{
|
||||
probe_t p = { .rail = rail };
|
||||
if ((r->io_lost & bit_of(rail)) == 0 &&
|
||||
i2cbus_xact(slot_mux_ch(rail), BRINGUP_LOCK_MS, read_io_fn, &p) == HAL_OK) {
|
||||
*arg = pca9555_efuse_fault(&p.in) ? BRINGUP_ARG_FLT : 0u;
|
||||
return pca9555_efuse_pg(&p.in) ? PG_OK : PG_WAIT;
|
||||
}
|
||||
*arg = BRINGUP_ARG_BY_VOLT;
|
||||
if ((r->blind & bit_of(rail)) == 0 &&
|
||||
i2cbus_xact(slot_mux_ch(rail), BRINGUP_LOCK_MS, read_vi_fn, &p) == HAL_OK) {
|
||||
return (p.vi.bus_mv >= rail_setpoint_mv(rail) - BRINGUP_PG_VOLT_MARGIN_MV) ? PG_OK
|
||||
: PG_WAIT;
|
||||
}
|
||||
return PG_BLIND;
|
||||
}
|
||||
|
||||
uint8_t bringup_want_update(uint8_t want, int rail, bool on)
|
||||
{
|
||||
if (rail < 1 || rail > PHONERAIL_RAIL_COUNT) {
|
||||
return want;
|
||||
}
|
||||
return on ? (uint8_t)(want | bit_of(rail)) : (uint8_t)(want & ~bit_of(rail));
|
||||
}
|
||||
|
||||
void bringup_power_restore(uint8_t want, bringup_report_t *r)
|
||||
{
|
||||
assert(r != NULL);
|
||||
const uint8_t all = (uint8_t)((1u << PHONERAIL_RAIL_COUNT) - 1u);
|
||||
want &= all;
|
||||
r->want = want;
|
||||
r->on = 0;
|
||||
r->pg_fail = 0;
|
||||
r->unverified = 0;
|
||||
|
||||
/* 能开的:想开、在位、mux 在。空槽且想开 = 刀片被拔走了(或 PRSNT# 虚接),记一条。 */
|
||||
uint8_t todo = 0;
|
||||
for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) {
|
||||
if ((want & bit_of(rail)) == 0) {
|
||||
continue;
|
||||
}
|
||||
if ((r->empty & bit_of(rail)) != 0) {
|
||||
evlog_put((uint8_t)rail, LOG_EV_SLOT_EMPTY, 0, 0, 0);
|
||||
continue;
|
||||
}
|
||||
if ((r->deg & BRINGUP_DEG_MUX) != 0) {
|
||||
continue; /* §5.8:mux 失联时五路电压电流全看不见 ⇒ 一路也不开 */
|
||||
}
|
||||
todo |= bit_of(rail);
|
||||
}
|
||||
|
||||
uint8_t pending = 0;
|
||||
uint32_t last_on = 0;
|
||||
bool any_on = false;
|
||||
int next = 1;
|
||||
|
||||
while (todo != 0 || pending != 0) {
|
||||
const uint32_t now = hal_time_now_ms();
|
||||
|
||||
/* §10.9 第 5 步:到点了就开下一路。**按上一路 EN 抬高的时刻算**,
|
||||
不按「上一路 PG 来了没有」算 —— 后者会让一路慢的拖住后面四路。 */
|
||||
if (todo != 0 && (!any_on || hal_time_elapsed_ms(last_on) >= BRINGUP_STAGGER_MS)) {
|
||||
while ((todo & bit_of(next)) == 0) {
|
||||
next++;
|
||||
}
|
||||
const int rail = next;
|
||||
todo &= (uint8_t)~bit_of(rail);
|
||||
if (rail_efuse_enable(rail, true) == HAL_OK) {
|
||||
r->on_ms[rail - 1] = now;
|
||||
r->on |= bit_of(rail);
|
||||
pending |= bit_of(rail);
|
||||
last_on = now;
|
||||
any_on = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* 第 6 步:每一路各自的 500 ms。 */
|
||||
for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) {
|
||||
if ((pending & bit_of(rail)) == 0) {
|
||||
continue;
|
||||
}
|
||||
uint8_t arg = 0;
|
||||
const pg_t pg = pg_of(rail, r, &arg);
|
||||
if (pg == PG_OK) {
|
||||
pending &= (uint8_t)~bit_of(rail);
|
||||
} else if (pg == PG_BLIND) {
|
||||
/* 看不见 ≠ 坏了(`ACT_RES_NO_PG` 同一条理由):开着,报「确认不了」。 */
|
||||
pending &= (uint8_t)~bit_of(rail);
|
||||
r->unverified |= bit_of(rail);
|
||||
} else if (hal_time_elapsed_ms(r->on_ms[rail - 1]) >= BRINGUP_PG_TIMEOUT_MS) {
|
||||
/* 等不到:关回去(§10.9 原文)。VBUS 在这一段里从没开过,只关 eFuse。 */
|
||||
(void)rail_efuse_enable(rail, false);
|
||||
pending &= (uint8_t)~bit_of(rail);
|
||||
r->on &= (uint8_t)~bit_of(rail);
|
||||
r->pg_fail |= bit_of(rail);
|
||||
evlog_put((uint8_t)rail, LOG_EV_PG_TIMEOUT, arg, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (todo != 0 || pending != 0) {
|
||||
hal_time_delay_ms(BRINGUP_PG_POLL_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户