- pCCU/CanBms:按《04KT38电池BCU-MBMS通信(CAN)定义》重写解码, BmsStatus 单状态模型改为 BcuNodeStatus 多节点模型(0x10XX00YY, 节点地址 01~36h),支持 0x0000 电压/电流/SOC/告警码、0x0001 单体 电压、0x0002 单体温度、0x0003 继电器、0x0006 绝缘/端口电压、 0x0010 告警位(附录1 中文码表)六类报文 - 平均单体温度偏移修正:协议文档 BYTE5 写"偏移0"有误,实测固件与 最高/最低一致均带 -40℃ 偏移(实车 0x10020002 原始 68/69 减 40 后 为 28/29℃,落在最低28~最高30区间内,按文档直读则超出物理范围) - pCCU/DbStore:新增 bcu_node 解析数据表,锂电池 BMS 报文每帧落一行 节点合成状态(原 comm_log 仅原始帧,BMS/CAN 帧此前不落 pCCU 库), buildReport 增加 BMS 记录数 - 快照/网页:BCU 按节点分组展示(告警位解析中文含义、数据 age), PM 状态报文锂电池/应急电池卡片 - pPowerManger:新增 iport 本地输入端口配置(UDP bind 延迟到 OnStartUp 读取配置后执行,保证 iport/ccuhost/ccuport 生效), 各 mission 文件补充注释 - test:CAN BCU 解码用例按新协议/新偏移更新(实车抓包 + 文档示例值), 133 项全部通过 - docs:删除旧 BMS 协议(xlsx/20230324docx),归档 04KT38 BCU-MBMS CAN 定义、配电控制器通信协议 20260824、配电系统 CAN 通讯协议 - scripts:新增 sync-board-time.sh,223 板卡(RK3588)时间校正 (本机为基准 + RTT 折半补偿对时,尽力写 RTC,支持 status/--time)
177 lines
6.7 KiB
Bash
Executable File
177 lines
6.7 KiB
Bash
Executable File
#!/bin/bash
|
||
#=======================================================================
|
||
# FILE: scripts/sync-board-time.sh
|
||
# DESC: 校正 223 板卡(RK3588,默认 192.168.0.223)的系统时间:以
|
||
# 本机时间(或 --time 指定时间)为基准,经 SSH 设置板卡系统时
|
||
# 钟,并尽力写入硬件时钟 (RTC)。板卡网络隔离无 NTP,用本脚本对时。
|
||
#
|
||
# 用法:
|
||
# ./scripts/sync-board-time.sh # 用本机时间校正板卡
|
||
# ./scripts/sync-board-time.sh status # 只查看时间与偏差
|
||
# ./scripts/sync-board-time.sh --time "2026-09-01 12:00:00"
|
||
# # 用指定时间校正(本地时区)
|
||
#
|
||
# 参数:
|
||
# --host <ip> 目标主机(默认 192.168.0.223)
|
||
# --user <user> 登录用户(默认 root)
|
||
# --time <str> 手动指定基准时间(date 可解析的格式,按本地时区解释)
|
||
# --keep-ntp 不执行 timedatectl set-ntp false
|
||
# --no-rtc 不写硬件时钟(跳过 hwclock --systohc)
|
||
# -h, --help 显示帮助
|
||
#
|
||
# 说明:
|
||
# - 需要 root 登录与免密 SSH(deploy.sh setup-ssh)。
|
||
# - 对时经 SSH 往返时延 (RTT) 折半补偿,精度约 ±0.1s(受网络抖动影响)。
|
||
# - 板卡若无可用 RTC,hwclock 失败仅告警;重启后时间可能回跳。
|
||
# - 对时会调整系统时钟,运行中的服务日志时间戳会跳变,属正常现象。
|
||
#=======================================================================
|
||
|
||
set -uo pipefail
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
||
HOST="192.168.0.223"
|
||
USER="root"
|
||
SET_TIME=""
|
||
KEEP_NTP=0
|
||
NO_RTC=0
|
||
|
||
info() { printf '\033[1;36m[time]\033[0m %s\n' "$*"; }
|
||
ok() { printf '\033[1;32m[time]\033[0m %s\n' "$*"; }
|
||
warn() { printf '\033[1;33m[time]\033[0m %s\n' "$*"; }
|
||
err() { printf '\033[1;31m[time]\033[0m %s\n' "$*"; }
|
||
|
||
usage() {
|
||
sed -n '2,26p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||
exit 0
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
# 参数解析
|
||
#-------------------------------------------------------------------
|
||
ACTION=""
|
||
while [ $# -gt 0 ]; do
|
||
case "$1" in
|
||
--host) [ $# -ge 2 ] || { err "--host 需要参数"; exit 1; }; HOST="$2"; shift 2 ;;
|
||
--user) [ $# -ge 2 ] || { err "--user 需要参数"; exit 1; }; USER="$2"; shift 2 ;;
|
||
--time) [ $# -ge 2 ] || { err "--time 需要参数"; exit 1; }; SET_TIME="$2"; shift 2 ;;
|
||
--keep-ntp) KEEP_NTP=1; shift ;;
|
||
--no-rtc) NO_RTC=1; shift ;;
|
||
status|help|-h|--help) ACTION="$1"; shift ;;
|
||
"") shift ;;
|
||
*) err "未知参数: $1(见 help)"; exit 1 ;;
|
||
esac
|
||
done
|
||
[ -n "${ACTION}" ] || ACTION="sync"
|
||
|
||
SSH_TARGET="${USER}@${HOST}"
|
||
SSH="ssh -o BatchMode=yes -o ConnectTimeout=5"
|
||
|
||
#-------------------------------------------------------------------
|
||
# 读取板卡时间并测 RTT
|
||
# 输出: "<epoch>|<板卡可读时间> <t0> <t1>"(t0/t1 为本机采样时刻)
|
||
#-------------------------------------------------------------------
|
||
read_board_time() {
|
||
local t0 t1 out
|
||
t0="$(date +%s.%N)"
|
||
out="$(${SSH} "${SSH_TARGET}" 'date "+%s.%N|%F %T %Z"' 2>/dev/null)" || {
|
||
err "无法免密 SSH 到 ${SSH_TARGET}(先执行: ./scripts/deploy.sh setup-ssh)" >&2
|
||
return 1
|
||
}
|
||
t1="$(date +%s.%N)"
|
||
printf '%s %.3f %.3f\n' "${out}" "${t0}" "${t1}"
|
||
}
|
||
|
||
# 从 read_board_time 输出解析: set -- <out> 后取 $1/$2/$3
|
||
parse_board_time() {
|
||
B_EPOCH="${1%%|*}"
|
||
B_DATE="${1#*|}"
|
||
T0="$2"
|
||
T1="$3"
|
||
MID="$(awk -v t0="${T0}" -v t1="${T1}" 'BEGIN{printf "%.3f", t0 + (t1-t0)/2}')"
|
||
DIFF="$(awk -v b="${B_EPOCH}" -v m="${MID}" 'BEGIN{printf "%+.3f", b - m}')"
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
# 命令: status
|
||
#-------------------------------------------------------------------
|
||
cmd_status() {
|
||
local out
|
||
out="$(read_board_time)" || return 1
|
||
parse_board_time ${out}
|
||
local rtt
|
||
rtt="$(awk -v t0="${T0}" -v t1="${T1}" 'BEGIN{printf "%.3f", t1-t0}')"
|
||
printf '本机时间: %s (RTT %.3fs)\n' "$(date -d "@${MID}" '+%F %T')" "${rtt}"
|
||
printf '板卡时间: %s\n' "${B_DATE}"
|
||
printf '偏差: 板卡比本机快 %s 秒\n' "${DIFF}"
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
# 命令: sync(默认)
|
||
#-------------------------------------------------------------------
|
||
cmd_sync() {
|
||
local out target board_reply
|
||
|
||
# 前置检查:SSH 连通 + 板卡 root 权限
|
||
out="$(read_board_time)" || return 1
|
||
parse_board_time ${out}
|
||
if ! ${SSH} "${SSH_TARGET}" '[ "$(id -u)" = 0 ]' 2>/dev/null; then
|
||
err "板卡登录用户需要 root 权限(当前 --user ${USER})"
|
||
return 1
|
||
fi
|
||
ok "SSH 连接正常: ${SSH_TARGET}"
|
||
info "当前偏差: 板卡比本机快 ${DIFF} 秒"
|
||
|
||
# 关闭 NTP 自动同步(板卡网络隔离本就无 NTP 源,防止干扰手动对时)
|
||
if [ "${KEEP_NTP}" = "0" ]; then
|
||
info "关闭板卡 NTP 自动同步 (timedatectl set-ntp false) ..."
|
||
${SSH} "${SSH_TARGET}" "command -v timedatectl >/dev/null 2>&1 && timedatectl set-ntp false || true"
|
||
fi
|
||
|
||
# 计算目标时间:手动指定值直接用;否则取本机时间 + RTT/2 补偿
|
||
if [ -n "${SET_TIME}" ]; then
|
||
target="$(date -d "${SET_TIME}" '+%s.%N' 2>/dev/null)" || {
|
||
err "无法解析时间: ${SET_TIME}"; return 1;
|
||
}
|
||
info "基准时间(手动): ${SET_TIME}"
|
||
else
|
||
local t2
|
||
t2="$(date +%s.%N)"
|
||
target="$(awk -v t2="${t2}" -v t0="${T0}" -v t1="${T1}" 'BEGIN{printf "%.3f", t2 + (t1-t0)/2}')"
|
||
info "基准时间(本机 + RTT/2 补偿)"
|
||
fi
|
||
info "设置板卡系统时间 -> $(date -d "@${target}" '+%F %T') ..."
|
||
|
||
board_reply="$(${SSH} "${SSH_TARGET}" "date -s @${target} 2>&1")" || {
|
||
err "date -s 失败: ${board_reply}"
|
||
return 1
|
||
}
|
||
ok "板卡返回: ${board_reply}"
|
||
|
||
# 写硬件时钟(无 RTC 时仅告警)
|
||
if [ "${NO_RTC}" = "0" ]; then
|
||
info "同步硬件时钟 (hwclock --systohc) ..."
|
||
if ${SSH} "${SSH_TARGET}" "hwclock --systohc" 2>/dev/null; then
|
||
ok "RTC 已同步"
|
||
else
|
||
warn "hwclock 失败(板卡可能无 RTC 或驱动未加载),重启后时间可能回跳"
|
||
fi
|
||
fi
|
||
|
||
# 校验
|
||
out="$(read_board_time)" || return 1
|
||
parse_board_time ${out}
|
||
info "校正后偏差: 板卡比本机快 ${DIFF} 秒"
|
||
ok "板卡时间: ${B_DATE}"
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
# 命令入口
|
||
#-------------------------------------------------------------------
|
||
case "${ACTION}" in
|
||
sync) cmd_sync ;;
|
||
status) cmd_status ;;
|
||
help|-h|--help) usage ;;
|
||
*) usage ;;
|
||
esac
|