Skip to content

T-Box 车载终端方案

T-Box 系统架构

硬件架构

┌─────────────────────────────────────────────────────────┐
│                    T-Box 硬件架构                         │
│                                                          │
│  电源管理                                                 │
│  ┌──────────────────────────────────────────────────┐   │
│  │  12V/24V 汽车电源 → 防反接 → 过压保护 → DC-DC    │   │
│  │  → 3.8V(模组)/ 3.3V(MCU)/ 1.8V(传感器)     │   │
│  └──────────────────────────────────────────────────┘   │
│                                                          │
│  核心处理                                                 │
│  ┌──────────┐  ┌──────────┐  ┌──────────────────────┐  │
│  │ 主控 SoC  │  │ 蜂窝模组  │  │    GNSS 模组          │  │
│  │ i.MX8M   │  │ RG520N   │  │    LC29H / LG69T     │  │
│  │ (NXP)    │  │ (5G)     │  │    (高精度+DR)        │  │
│  └──────────┘  └──────────┘  └──────────────────────┘  │
│                                                          │
│  车辆接口                                                 │
│  ┌──────────┐  ┌──────────┐  ┌──────────────────────┐  │
│  │ CAN FD   │  │ LIN 总线  │  │    以太网(100BASE-T1)│  │
│  │ 控制器   │  │ 控制器   │  │    车载以太网          │  │
│  └──────────┘  └──────────┘  └──────────────────────┘  │
│                                                          │
│  存储与安全                                               │
│  ┌──────────┐  ┌──────────┐  ┌──────────────────────┐  │
│  │ eMMC 32G │  │ HSM 安全  │  │    加速度传感器        │  │
│  │ 数据存储  │  │ 芯片     │  │    (碰撞检测)        │  │
│  └──────────┘  └──────────┘  └──────────────────────┘  │
└─────────────────────────────────────────────────────────┘

软件架构

应用层:
  TSP 通信客户端 / OTA 管理 / 数据采集 / eCall

中间件:
  MQTT 客户端 / TLS 安全 / 数据压缩 / 日志管理

操作系统:
  Linux(Yocto)或 Android Automotive

驱动层:
  CAN 驱动 / GNSS 驱动 / 蜂窝驱动 / 传感器驱动

CAN 总线数据采集

CAN FD 配置

c
#include <linux/can.h>
#include <linux/can/raw.h>
#include <sys/socket.h>
#include <net/if.h>

// 打开 CAN 接口
int open_can_socket(const char *interface) {
    int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    
    struct ifreq ifr;
    strcpy(ifr.ifr_name, interface);
    ioctl(sock, SIOCGIFINDEX, &ifr);
    
    struct sockaddr_can addr = {
        .can_family = AF_CAN,
        .can_ifindex = ifr.ifr_ifindex
    };
    
    bind(sock, (struct sockaddr *)&addr, sizeof(addr));
    return sock;
}

// 读取 CAN 帧
void read_can_data(int sock) {
    struct can_frame frame;
    
    while (1) {
        int nbytes = read(sock, &frame, sizeof(frame));
        if (nbytes < 0) break;
        
        printf("CAN ID: 0x%03X, DLC: %d, Data:", 
               frame.can_id, frame.can_dlc);
        for (int i = 0; i < frame.can_dlc; i++) {
            printf(" %02X", frame.data[i]);
        }
        printf("\n");
        
        // 解析特定 CAN 消息
        parse_can_message(frame.can_id, frame.data, frame.can_dlc);
    }
}

// 解析车辆 CAN 消息(示例:车速)
void parse_can_message(uint32_t can_id, uint8_t *data, uint8_t dlc) {
    switch (can_id) {
        case 0x3B3:  // 车速(示例 ID,实际因车型而异)
            {
                uint16_t speed_raw = (data[0] << 8) | data[1];
                float speed = speed_raw * 0.01f;  // 0.01 km/h 分辨率
                printf("Vehicle Speed: %.1f km/h\n", speed);
            }
            break;
            
        case 0x3D9:  // 发动机转速
            {
                uint16_t rpm_raw = (data[2] << 8) | data[3];
                float rpm = rpm_raw * 0.25f;  // 0.25 RPM 分辨率
                printf("Engine RPM: %.0f\n", rpm);
            }
            break;
    }
}

TSP 通信协议

MQTT 上报格式

json
// 车辆状态上报(每30秒)
{
  "vin": "LSVNV2182E2100001",
  "timestamp": 1716192000,
  "location": {
    "lat": 31.2304,
    "lng": 121.4737,
    "altitude": 10.5,
    "speed": 60.5,
    "heading": 90.0,
    "accuracy": 1.5
  },
  "vehicle": {
    "speed": 60.5,
    "rpm": 2000,
    "fuel_level": 75,
    "coolant_temp": 90,
    "odometer": 12345.6,
    "gear": "D"
  },
  "battery": {
    "voltage": 12.8,
    "soc": 85
  },
  "network": {
    "rsrp": -85,
    "sinr": 15,
    "operator": "46000"
  }
}

远程控制指令

json
// TSP 下发远程控制指令
{
  "cmd_id": "CMD_20240520_001",
  "vin": "LSVNV2182E2100001",
  "timestamp": 1716192000,
  "command": "remote_lock",
  "params": {
    "action": "lock",
    "timeout": 30
  }
}

// T-Box 响应
{
  "cmd_id": "CMD_20240520_001",
  "vin": "LSVNV2182E2100001",
  "timestamp": 1716192005,
  "result": "success",
  "message": "Vehicle locked successfully"
}

OTA 升级方案

整车 OTA 架构

OTA 服务器(云端)
  ↓ HTTPS 下载
T-Box(下载和验证固件包)
  ↓ CAN/以太网
各 ECU(接收固件,执行升级)
  - 发动机 ECU
  - 变速箱 ECU
  - 车身控制 ECU
  - 仪表盘 ECU

T-Box OTA 实现

c
// OTA 升级流程
typedef enum {
    OTA_STATE_IDLE,
    OTA_STATE_CHECKING,
    OTA_STATE_DOWNLOADING,
    OTA_STATE_VERIFYING,
    OTA_STATE_INSTALLING,
    OTA_STATE_COMPLETE,
    OTA_STATE_FAILED
} OTAState;

typedef struct {
    OTAState state;
    char version[32];
    char download_url[256];
    uint32_t file_size;
    uint32_t downloaded;
    uint8_t md5[16];
} OTAContext;

// 检查更新
int ota_check_update(OTAContext *ctx) {
    // 向 OTA 服务器查询最新版本
    char url[256];
    snprintf(url, sizeof(url), 
             "https://ota.example.com/check?vin=%s&version=%s",
             get_vin(), get_current_version());
    
    // HTTP GET 请求
    char response[4096];
    int ret = http_get(url, response, sizeof(response));
    if (ret != 0) return -1;
    
    // 解析响应
    cJSON *json = cJSON_Parse(response);
    if (cJSON_GetObjectItem(json, "has_update")->valueint) {
        strncpy(ctx->version, 
                cJSON_GetObjectItem(json, "version")->valuestring, 32);
        strncpy(ctx->download_url,
                cJSON_GetObjectItem(json, "url")->valuestring, 256);
        ctx->file_size = cJSON_GetObjectItem(json, "size")->valueint;
        ctx->state = OTA_STATE_DOWNLOADING;
        return 1;  // 有更新
    }
    
    cJSON_Delete(json);
    return 0;  // 无更新
}

// 下载固件(断点续传)
int ota_download(OTAContext *ctx) {
    FILE *fp = fopen("/tmp/firmware.bin", "wb");
    
    // 支持断点续传
    long resume_pos = get_resume_position();
    
    char range_header[64];
    snprintf(range_header, sizeof(range_header), 
             "Range: bytes=%ld-", resume_pos);
    
    // HTTP 下载(带进度回调)
    http_download(ctx->download_url, fp, range_header, 
                  ota_progress_callback, ctx);
    
    fclose(fp);
    return 0;
}

eCall 紧急救援

eCall 是欧盟强制要求的车辆紧急呼叫系统(EU 2015/758 法规):

c
// eCall 触发条件
typedef enum {
    ECALL_TRIGGER_MANUAL,    // 手动触发(按钮)
    ECALL_TRIGGER_AUTO_CRASH // 自动触发(碰撞传感器)
} ECallTrigger;

// 碰撞检测
void check_crash_sensor(void) {
    // 读取加速度传感器
    float ax, ay, az;
    read_accelerometer(&ax, &ay, &az);
    
    // 计算合加速度
    float total_g = sqrt(ax*ax + ay*ay + az*az);
    
    // 超过阈值(通常 4-8g)触发 eCall
    if (total_g > 6.0f) {
        trigger_ecall(ECALL_TRIGGER_AUTO_CRASH);
    }
}

// 触发 eCall
void trigger_ecall(ECallTrigger trigger) {
    // 1. 获取当前位置
    GNSSData location;
    get_gnss_location(&location);
    
    // 2. 构建 MSD(最小数据集)
    MSD msd = {
        .message_identifier = 1,
        .control = {
            .test_call = 0,
            .position_can_be_trusted = 1,
            .vehicle_type = VEHICLE_TYPE_PASSENGER_CAR
        },
        .timestamp = get_utc_time(),
        .vehicle_location = {
            .latitude = (int32_t)(location.latitude * 1e7),
            .longitude = (int32_t)(location.longitude * 1e7)
        },
        .vin = get_vin()
    };
    
    // 3. 拨打 eCall 号码(欧洲:112,中国:120)
    make_ecall_call("112", &msd);
}

褚成志的笔记