Files
H100PowerManger/scripts/build-board.sh
T
zjk b547772709 新增 pCanBridge:USBCAN-8E-U CAN->MOOSDB 透传桥 + SQLite 落库
新应用 src/pCanBridge(独立 MOOS App,单通道):
- CanEndpoint:TCP Client 连接 CANET/USBCAN-8E-U 工作端口
  (目标 IP/端口可配置,默认 192.168.0.222:4001=CAN0),
  接收线程流式缓冲按 13 字节切帧,过滤无效 DLC(>8),
  断线自动重连(非阻塞 connect+超时 / SO_RCVTIMEO 读超时)。
- 帧协议(CANET-8E-U 手册 8.1):byte0=帧信息(bit7 FF/bit6 RTR/
  bit3~0 DLC),byte1~4=ID 大端,byte5~12=数据。
- MOOS 映射:变量名 CAN_0x%08X=CAN ID(不缩减),m_sVal=二进制
  data(逐帧透传不限流),m_sSrcAux=通道名(can_channel_name),
  m_dfVal2=原始帧信息字节(用于区分标准/扩展、数据/远程帧)。
- CanDbStore:每帧落库 SQLite(can_frame 表:time/channel/
  frame_info/can_id/dlc/hex,含 time、can_id 索引),参考 pCCU
  DbStore:预处理语句 + WAL + synchronous=NORMAL,路径由 dbpath
  配置;复用 pPowerManger 的 sqlite3 amalgamation。
- AppCast 输出连接状态/收帧/发布/落库统计。

配套:
- missions/h100.moos 新增 pCanBridge 配置块(板卡 dbpath 指向
  data 目录)。
- build-board.sh / deploy.sh 支持 pCanBridge:产物部署 +
  pCanBridge.service 安装,服务列表加入第 5 个服务。
- .gitignore 忽略 bin/pCanBridge 与本机默认数据库。

已验证(板卡 192.168.0.223 实测):服务 active,连接设备正常,
~60 帧/s 透传,落库 9000+ 行 integrity ok、无丢帧。
2026-08-31 19:14:59 +08:00

262 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
#=======================================================================
# FILE: scripts/build-board.sh
# DESC: 把源码同步到目标板卡 (RK3588 / Ubuntu 22.04),在板卡原生编译
# (aarch64 直编,比本地 QEMU 模拟快约 10 倍),并把产物部署到
# /root/work/h100/bin/,可选重启 systemd 服务。
#
# 用法:
# ./scripts/build-board.sh # 同步+编译+部署(不重启)
# ./scripts/build-board.sh --start # 编译后重启全部服务(含 pCanBridge)
# ./scripts/build-board.sh --clean # 板卡上重新 cmake 再编译
# ./scripts/build-board.sh --jobs 4 # 指定并行度(默认板卡 nproc)
#
# 参数:
# --host <ip> 目标主机(默认 192.168.0.223)
# --user <user> 登录用户(默认 root)
# --board-src <dir> 板卡源码目录(默认 /root/work/h100/src)
# --board-bin <dir> 板卡部署目录(默认 /root/work/h100/bin)
# --jobs <n> 编译并行度(默认板卡 nproc)
# --start 编译部署后重启服务
# --clean 先重新 cmake(配置变更时用)
# --ccu-host <ip> 覆盖 mission 中 pPowerManger 的 CCU 地址 (ccuhost)
# --ccu-port <n> 覆盖 mission 中 pPowerManger 的 CCU 端口 (ccuport)
# -h, --help 显示帮助
#
# 前置: 板卡已配免密 SSH,且有编译环境(cmake/g++/MOOS/jsoncpp),
# 源码已能本地编译(本脚本只负责同步+板卡编译)。
#
# !!!! 板卡网络配置(2026-08-26 联调定型,勿随意修改) !!!!
#
# 板卡与 FC 的组网为"单网卡 + /23 掩码"方案(依据《超滑FC和复合管控器
# 通讯协议-0821》1.1.1:CCU 192.168.0.140/23 <-> FC 192.168.1.162):
#
# enP3p49s0 192.168.0.223/23 (255.255.254.0) <- 唯一业务网口,接交换机
# /23 使 192.168.0.x 与 192.168.1.x 同子网直达,
# FC(192.168.1.162) 无需网关即可互通。
# NM 配置档案: "有线连接 1"(静态 manual,已持久化)
# enP4p65s0 已弃用(旧双网卡方案的 FC 专口,物理链路已断)
# 回环 lo pPowerManger(5001) <-> pCCU(7000) 同机 UDP 互通
#
# 关联端口:
# FC 状态: FC:7000 -> 板卡:6000 (pCCU 监听)
# FC 控制: 板卡:6000 -> FC:7000 (pCCU 发送)
# PM 指令: pPowerManger:5001 -> pCCU:7000 (127.0.0.1,
# 见 missions/h100.moos ccuhost/ccuport,默认值在 PowerManger.h CCUHOST)
# PM 状态: pCCU:7000 -> pPowerManger:5001 (127.0.0.1)
#
# 排障提示:
# - 若收不到 FC 状态,先在板卡上 `ethtool enP3p49s0` 看 Link detected,
# 再 `ping 192.168.1.162`;ping 不通通常是物理链路/交换机问题,
# 不要改回 /24 掩码或启用 enP4p65s0 来"修"网络。
# - 改 IP/掩码须用 `nmcli con mod "有线连接 1" ...` 持久化,
# 并保持掩码 /23。
#=======================================================================
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")"
HOST="192.168.0.223"
USER="root"
BOARD_SRC="/root/work/h100/src"
BOARD_BIN="/root/work/h100/bin"
JOBS=""
DO_START=0
DO_CLEAN=0
CCU_HOST=""
CCU_PORT=""
SERVICES=(moosdb pPowerManger pPowerMangerHost pCCU pCanBridge)
info() { printf '\033[1;36m[build-board]\033[0m %s\n' "$*"; }
ok() { printf '\033[1;32m[build-board]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[build-board]\033[0m %s\n' "$*"; }
err() { printf '\033[1;31m[build-board]\033[0m %s\n' "$*"; }
usage() {
sed -n '2,31p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
exit 0
}
#-------------------------------------------------------------------
# 参数解析
#-------------------------------------------------------------------
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 ;;
--board-src) [ $# -ge 2 ] || { err "--board-src 需要参数"; exit 1; }; BOARD_SRC="$2"; shift 2 ;;
--board-bin) [ $# -ge 2 ] || { err "--board-bin 需要参数"; exit 1; }; BOARD_BIN="$2"; shift 2 ;;
--jobs) [ $# -ge 2 ] || { err "--jobs 需要参数"; exit 1; }; JOBS="$2"; shift 2 ;;
--start) DO_START=1; shift ;;
--clean) DO_CLEAN=1; shift ;;
--ccu-host) [ $# -ge 2 ] || { err "--ccu-host 需要参数"; exit 1; }; CCU_HOST="$2"; shift 2 ;;
--ccu-port) [ $# -ge 2 ] || { err "--ccu-port 需要参数"; exit 1; }; CCU_PORT="$2"; shift 2 ;;
-h|--help) usage ;;
*) err "未知参数: $1(见 --help)"; exit 1 ;;
esac
done
SSH_TARGET="${USER}@${HOST}"
SSH="ssh -o BatchMode=yes -o ConnectTimeout=5"
case "${CCU_PORT}" in
""|*[!0-9]*) [ -z "${CCU_PORT}" ] || { err "--ccu-port 必须是数字端口: ${CCU_PORT}"; exit 1; } ;;
esac
#-------------------------------------------------------------------
# 1. 前置检查
#-------------------------------------------------------------------
if ! ${SSH} "${SSH_TARGET}" 'true' 2>/dev/null; then
err "无法免密 SSH 到 ${SSH_TARGET}"
err "请先配置免密登录: ssh-copy-id ${SSH_TARGET}"
exit 1
fi
ok "SSH 连接正常: ${SSH_TARGET}"
#-------------------------------------------------------------------
# mission 中插入/替换 "key = value"(键已存在则替换,否则插到第一个
# 顶层 '}' 之前,即 pPowerManger 配置块末尾)
#-------------------------------------------------------------------
upsert_moos_param() {
local f="$1" key="$2" val="$3"
if grep -qE "^[[:space:]]*${key}[[:space:]]*=" "${f}"; then
sed -i -E "s|^([[:space:]]*)${key}[[:space:]]*=.*|\1${key} = ${val}|" "${f}"
else
awk -v kv=" ${key} = ${val}" \
'!d && /^[[:space:]]*}[[:space:]]*$/ { print kv; d=1 } { print }' \
"${f}" > "${f}.tmp" && mv "${f}.tmp" "${f}"
fi
}
#-------------------------------------------------------------------
# 2. 同步源码到板卡(排除构建产物 / git / 数据)
#-------------------------------------------------------------------
info "同步源码到板卡 ${BOARD_SRC} ..."
rsync -az --delete \
--exclude='build/' \
--exclude='build-arm64/' \
--exclude='build-native/' \
--exclude='build-nosa-test/' \
--exclude='bin/' \
--exclude='.git/' \
--exclude='.cache/' \
--exclude='.kilo/' \
--exclude='.vscode/' \
--exclude='docs/' \
--exclude='reports/' \
--exclude='*.log' \
--exclude='*.db' \
--exclude='CMakeCache.txt' \
"${PROJECT_ROOT}/" "${SSH_TARGET}:${BOARD_SRC}/" || { err "rsync 源码失败"; exit 1; }
ok "源码已同步"
if [ -f "${PROJECT_ROOT}/missions/h100.moos" ]; then
info "同步 mission h100.moos ..."
local_mission="${PROJECT_ROOT}/missions/h100.moos"
tmp_moos=""
if [ -n "${CCU_HOST}" ] || [ -n "${CCU_PORT}" ]; then
tmp_moos="$(mktemp)"
cp "${local_mission}" "${tmp_moos}"
[ -n "${CCU_HOST}" ] && upsert_moos_param "${tmp_moos}" ccuhost "${CCU_HOST}"
[ -n "${CCU_PORT}" ] && upsert_moos_param "${tmp_moos}" ccuport "${CCU_PORT}"
local_mission="${tmp_moos}"
info "CCU 地址覆盖: ccuhost=${CCU_HOST:-<保持原值>} ccuport=${CCU_PORT:-<保持原值>}"
fi
rsync -az "${local_mission}" \
"${SSH_TARGET}:/root/work/h100/missions/h100.moos" || { err "rsync mission 失败"; [ -n "${tmp_moos}" ] && rm -f "${tmp_moos}"; exit 1; }
[ -n "${tmp_moos}" ] && rm -f "${tmp_moos}"
ok "mission 已同步"
fi
#-------------------------------------------------------------------
# 3. 板卡原生编译
#-------------------------------------------------------------------
if [ "${DO_CLEAN}" = "1" ]; then
info "重新 cmake(--clean)..."
${SSH} "${SSH_TARGET}" "rm -rf ${BOARD_SRC}/build-native && mkdir -p ${BOARD_SRC}/build-native && \
cd ${BOARD_SRC}/build-native && cmake -DCMAKE_BUILD_TYPE=Release .." \
|| { err "cmake 失败"; exit 1; }
ok "cmake 完成"
else
${SSH} "${SSH_TARGET}" "mkdir -p ${BOARD_SRC}/build-native"
# 若首次未配置过则先 cmake
if ! ${SSH} "${SSH_TARGET}" "[ -f ${BOARD_SRC}/build-native/Makefile ]"; then
info "首次编译,先 cmake ..."
${SSH} "${SSH_TARGET}" "cd ${BOARD_SRC}/build-native && cmake -DCMAKE_BUILD_TYPE=Release .." \
|| { err "cmake 失败"; exit 1; }
ok "cmake 完成"
fi
fi
if [ -z "${JOBS}" ]; then
JOBS="$(${SSH} "${SSH_TARGET}" nproc)"
fi
info "板卡编译 (make -j${JOBS}) ..."
if ! ${SSH} "${SSH_TARGET}" "cd ${BOARD_SRC}/build-native && make -j${JOBS}"; then
err "板卡编译失败(见上方输出)"
exit 1
fi
ok "板卡编译完成"
#-------------------------------------------------------------------
# 4. 部署产物到板卡运行目录
#-------------------------------------------------------------------
info "部署产物到 ${BOARD_BIN}/ ..."
${SSH} "${SSH_TARGET}" "mkdir -p ${BOARD_BIN} && \
cp -f ${BOARD_SRC}/bin/pPowerManger ${BOARD_BIN}/pPowerManger && \
cp -f ${BOARD_SRC}/bin/pPowerMangerHost ${BOARD_BIN}/pPowerMangerHost && \
cp -f ${BOARD_SRC}/bin/pCCU ${BOARD_BIN}/pCCU && \
cp -f ${BOARD_SRC}/bin/pCanBridge ${BOARD_BIN}/pCanBridge && \
chmod +x ${BOARD_BIN}/pPowerManger ${BOARD_BIN}/pPowerMangerHost ${BOARD_BIN}/pCCU ${BOARD_BIN}/pCanBridge" \
|| { err "部署产物失败"; exit 1; }
ok "产物已部署"
#-------------------------------------------------------------------
# 4.5 安装/刷新 pCanBridge systemd unit(幂等,其它 4 个 unit 已装)
#-------------------------------------------------------------------
info "安装 pCanBridge.service ..."
${SSH} "${SSH_TARGET}" "cat > /etc/systemd/system/pCanBridge.service" <<EOF
[Unit]
Description=pCanBridge for H100 Power Manager
After=moosdb.service
Requires=moosdb.service
[Service]
Type=simple
WorkingDirectory=${BOARD_BIN}
ExecStart=${BOARD_BIN}/pCanBridge --alias=pCanBridge /root/work/h100/missions/h100.moos
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
${SSH} "${SSH_TARGET}" "systemctl daemon-reload && systemctl reset-failed pCanBridge 2>/dev/null || true"
ok "pCanBridge.service 已安装"
echo ""
ok "产物: ${BOARD_BIN}/pPowerManger (aarch64)"
${SSH} "${SSH_TARGET}" "file ${BOARD_BIN}/pPowerManger | cut -c1-60"
#-------------------------------------------------------------------
# 5. 可选重启服务
#-------------------------------------------------------------------
if [ "${DO_START}" = "1" ]; then
info "重启服务 ..."
${SSH} "${SSH_TARGET}" "systemctl restart ${SERVICES[*]}" \
|| { err "重启服务失败"; exit 1; }
sleep 3
ok "服务状态: $(${SSH} "${SSH_TARGET}" "systemctl is-active ${SERVICES[*]}")"
else
echo ""
info "未重启服务。需要重启请加 --start 或手动:"
echo " systemctl restart ${SERVICES[*]}"
fi
echo ""
ok "完成。"