少妇被躁爽到高潮无码人狍大战,欧洲亚洲国产精华液,色狠狠色噜噜av天堂一区,人人妻,一区二区三区,色偷偷wwww88888

首頁 - 關(guān)于研博 - 技術(shù)筆記 - 電動汽車GB/T32960-2016協(xié)議介紹開發(fā)
電動汽車GB/T32960-2016協(xié)議介紹開發(fā)
2025.02.21

一、協(xié)議介紹

在GB/T32960-2016協(xié)議中規(guī)定了電動汽車遠(yuǎn)程服務(wù)于管理系統(tǒng)中協(xié)議結(jié)構(gòu)、通信連接、數(shù)據(jù)包結(jié)構(gòu)與定義、數(shù)據(jù)單元格式與定義。本協(xié)議采用大端模式的網(wǎng)絡(luò)字節(jié)序來傳遞字和雙字。

協(xié)議中傳輸?shù)臄?shù)據(jù)類型如下:

 

通訊包結(jié)構(gòu)組成如下:

命令標(biāo)識定義如下:

 

應(yīng)答標(biāo)志定義如下:

時間定義如下:

數(shù)據(jù)單元格式和定義

本次只有車輛登入的報文解析,車輛登入的數(shù)據(jù)格式和定義如下:

更多關(guān)于GB/T32960-2016的內(nèi)容可點擊查看。

二、協(xié)議解析開發(fā)

本次協(xié)議解析基于研博工業(yè)物聯(lián)網(wǎng)統(tǒng)一接入系統(tǒng)(stew-ot)協(xié)議擴(kuò)展規(guī)范開發(fā)。示例只針對GB/T32960-2016協(xié)議的車輛登入數(shù)據(jù)解碼,不涉及對該類設(shè)備的控制。

新建類com.yanboot.iot.protocol.tcp.GBT32960.GBT32960ProtocolCodec,根據(jù)SDK包開發(fā)規(guī)范完成協(xié)議報文的解析工作。

  • 實現(xiàn)com.yanboot.iot.sdk.protocol.ProtocolCodec接口,重寫support方法,指定協(xié)議的唯一標(biāo)識、名稱、特性等內(nèi)容。

@Override
public ProtocolSupport support() {
    return new ProtocolSupport(TransportProtocol.TCP)
    .id("GB/T 32960.3-2016")
    .name("GB/T 32960-2016《電動汽車遠(yuǎn)程服務(wù)與管理技術(shù)規(guī)范》")
    .feature(new ProtocolFeature().keepOnline(true).keepOnlineTimeoutSeconds(1800))
    .description("GB/T 32960-2016《電動汽車遠(yuǎn)程服務(wù)與管理技術(shù)規(guī)范》")
    ;
}
  • 實現(xiàn)com.yanboot.iot.sdk.protocol.ProtocolCodec接口的decode方法,完成協(xié)議的解碼工作。

@Override
public void decode(OperatorSupplier supplier, DeviceSession deviceSession, ProtocolMessage message, MessageExporter> messageExporter) {
    TcpProtocolMessage tcpProtocolMessage = (TcpProtocolMessage) message;
    byte[] payload = tcpProtocolMessage.payloadAsBytes();

    //起始符
    if (START_BIT != payload[0] || START_BIT != payload[1]) {
        log.error("數(shù)據(jù)包起始符不正確,請檢查數(shù)據(jù)包數(shù)據(jù)!{}", Arrays.toString(payload));
        return;
    }
    //校驗碼
    if (!checkSum(payload)) {
        log.error("數(shù)據(jù)包校驗碼校驗不正確,請檢查數(shù)據(jù)包數(shù)據(jù)!{}", Arrays.toString(payload));
        return;
    }
    //命令標(biāo)識
    String command = COMMAND_MAP.get(payload[2] + "");
    //應(yīng)答標(biāo)志
    String reply = ANSWER_MAP.get(payload[3] + "");
    //唯一識別碼
    StringBuffer vin = new StringBuffer();
    for (int i = 4; i < 21; i++) {
        vin.append(payload[i]);
    }
    //數(shù)據(jù)單元加密方式
    String encrypt = ENCRYPT_MAP.get(payload[21] + "");
    //數(shù)據(jù)單元長度
    int dataLen = Integer.parseInt(payload[22] + "" + payload[23], 16);
    //數(shù)據(jù)單元
    byte[] data = Arrays.copyOfRange(payload, 24, 24 + dataLen);
    Map dataMap = parseData(command, data);
    if (ObjectUtil.isNull(dataMap)) {
        return;
    }
    dataMap.put("command", command);
    dataMap.put("reply", reply);
    dataMap.put("encrypt", encrypt);
    messageExporter.export(new ReportPropertyMessage().deviceId(vin.toString()).properties(dataMap).timestamp(Long.parseLong(dataMap.getOrDefault("datetime",System.currentTimeMillis()).toString())));
}
  • 完整代碼如下:

package com.yanboot.iot.protocol.tcp.GBT32960;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.yanboot.iot.core.constant.TransportProtocol;
import com.yanboot.iot.core.message.device.DeviceMessage;
import com.yanboot.iot.core.message.device.impl.ReportPropertyMessage;
import com.yanboot.iot.core.message.protocol.ProtocolMessage;
import com.yanboot.iot.core.message.protocol.impl.TcpProtocolMessage;
import com.yanboot.iot.core.operator.OperatorSupplier;
import com.yanboot.iot.core.session.DeviceSession;
import com.yanboot.iot.sdk.protocol.MessageExporter;
import com.yanboot.iot.sdk.protocol.ProtocolCodec;
import com.yanboot.iot.sdk.protocol.ProtocolFeature;
import com.yanboot.iot.sdk.protocol.ProtocolSupport;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 *
 */
@Slf4j
public class GBT32960ProtocolCodec implements ProtocolCodec {
    private final static byte START_BIT = 0X23;
    private final static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyMMddHHmmss");

    //命令標(biāo)識
    private final static Map COMMAND_MAP = new HashMap();
    //應(yīng)答標(biāo)識
    private final static Map ANSWER_MAP = new HashMap();
    //加密方式
    private final static Map ENCRYPT_MAP = new HashMap();

    static {
        // 定義命令標(biāo)識
        COMMAND_MAP.put("01", "車輛登入");
        COMMAND_MAP.put("02", "實時信息上報");
        COMMAND_MAP.put("03", "補發(fā)信息上報");
        COMMAND_MAP.put("04", "車輛登出");
        COMMAND_MAP.put("05", "平臺登入");
        COMMAND_MAP.put("06", "平臺登出");
        // 定義應(yīng)答標(biāo)識
        ANSWER_MAP.put("01", "成功");
        ANSWER_MAP.put("02", "錯誤");
        ANSWER_MAP.put("03", "VIN重復(fù)");
        ANSWER_MAP.put("FE", "命令");
        // 定義加密方式
        ENCRYPT_MAP.put("01", "數(shù)據(jù)不加密");
        ENCRYPT_MAP.put("02", "數(shù)據(jù)經(jīng)過RSA算法加密");
        ENCRYPT_MAP.put("03", "數(shù)據(jù)經(jīng)過AES128位算法加密");
        ENCRYPT_MAP.put("FE", "異常");
        ENCRYPT_MAP.put("FF", "無效");
    }

    @Override
    public ProtocolSupport support() {
        return new ProtocolSupport(TransportProtocol.TCP)
                .id("GB/T 32960.3-2016")
                .name("GB/T 32960-2016《電動汽車遠(yuǎn)程服務(wù)與管理技術(shù)規(guī)范》")
                .feature(new ProtocolFeature().keepOnline(true).keepOnlineTimeoutSeconds(30))
                .description("GB/T 32960-2016《電動汽車遠(yuǎn)程服務(wù)與管理技術(shù)規(guī)范》")
                ;
    }


    /**
     * 解碼
     */
    @Override
    public void decode(OperatorSupplier supplier, DeviceSession deviceSession, ProtocolMessage message, MessageExporter> messageExporter) {
        TcpProtocolMessage tcpProtocolMessage = (TcpProtocolMessage) message;
        byte[] payload = tcpProtocolMessage.payloadAsBytes();

        //起始符
        if (START_BIT != payload[0] || START_BIT != payload[1]) {
            log.error("數(shù)據(jù)包起始符不正確,請檢查數(shù)據(jù)包數(shù)據(jù)!{}", Arrays.toString(payload));
            return;
        }
        //校驗碼
        if (!checkSum(payload)) {
            log.error("數(shù)據(jù)包校驗碼校驗不正確,請檢查數(shù)據(jù)包數(shù)據(jù)!{}", Arrays.toString(payload));
            return;
        }
        //命令標(biāo)識
        String command = COMMAND_MAP.get(payload[2] + "");
        //應(yīng)答標(biāo)志
        String reply = ANSWER_MAP.get(payload[3] + "");
        //唯一識別碼
        StringBuffer vin = new StringBuffer();
        for (int i = 4; i < 21; i++) {
            vin.append(payload[i]);
        }
        //數(shù)據(jù)單元加密方式
        String encrypt = ENCRYPT_MAP.get(payload[21] + "");
        //數(shù)據(jù)單元長度
        int dataLen = Integer.parseInt(payload[22] + "" + payload[23], 16);
        //數(shù)據(jù)單元
        byte[] data = Arrays.copyOfRange(payload, 24, 24 + dataLen);
        Map dataMap = parseData(command, data);
        if (ObjectUtil.isNull(dataMap)) {
            return;
        }
        dataMap.put("command", command);
        dataMap.put("reply", reply);
        dataMap.put("encrypt", encrypt);
        messageExporter.export(new ReportPropertyMessage().deviceId(vin.toString()).properties(dataMap).timestamp(Long.parseLong(dataMap.getOrDefault("datetime",System.currentTimeMillis()).toString())));
    }

    /**
     * 解析數(shù)據(jù)
     *
     * @param command 命令標(biāo)識
     * @param data    數(shù)據(jù)單元
     * @return 解析結(jié)果
     */
    private Map parseData(String command, byte[] data) {

        switch (command) {
            case "01" -> {
                return carLogin(data);
            }
        }
        return null;
    }

    /**
     * 車輛登入
     */
    private Map carLogin(byte[] data) {
        Map dataMap = new HashMap<>();
        StringBuilder datetime = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            byte datum = data[i];
            if (datum < 10) {
                datetime.append("0");
            }
            datetime.append(datum);
        }
        dataMap.put("datetime", LocalDateTime.parse(datetime.toString(),dtf).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        dataMap.put("loginSequenceNumber", Integer.parseInt(data[6] + "" + data[7], 16) + "");
        StringBuilder iccid = new StringBuilder();
        for (int i = 8; i < 28; i++) {
            iccid.append(data[i]);
        }
        dataMap.put("ICCID", iccid.toString());
        dataMap.put("energyStorageNumber", Integer.parseInt(data[28] + "", 16) + "");
        dataMap.put("energyStorageLength", Integer.parseInt(data[29] + "", 16) + "");
        int length = data.length;
        StringBuilder energyStorageCode = new StringBuilder();
        for (int i = 30; i < length; i++) {
            energyStorageCode.append(data[i]);
        }
        dataMap.put("energyStorageCode", energyStorageCode.toString());
        return dataMap;
    }


    /**
     * 校驗碼校驗
     */
    public static boolean checkSum(byte[] payload) {
        int checkCode = Integer.parseInt(payload[payload.length - 1] + "", 16);
        int a = 0;
        for (int i = 2; i < payload.length - 2; i++) {
            a = a ^ Integer.parseInt(payload[i] + "", 16);
        }
        return checkCode == a;
    }
}

三、適用場景

GB/T 32960-2016《電動汽車遠(yuǎn)程服務(wù)與管理技術(shù)規(guī)范》適用于以下場景中:

(1):電動汽車健康監(jiān)測;

(2):車輛使用記錄;

(3):故障診斷;

(4):車企和政府的數(shù)據(jù)共享平臺等。

獲取相關(guān)資料
下載地址將會發(fā)送至您填寫的郵箱
相關(guān)新聞
IEC104協(xié)議解析
2025-03-07
HJ212環(huán)境監(jiān)測數(shù)據(jù)傳輸協(xié)議
2025-02-14
電能表DLT645協(xié)議解析
2025-02-07
  • 在線客服
  • 電話咨詢
  • 微信
  • 短視頻