【论文代码】基于隐蔽带宽的汽车控制网路鲁棒认证-到达时间间隔通道的Java实现(一)

文章目录

  • 一、USBtin 基类
    • 1.1 CANSender 类
      • 1.1.1 SimpleSender类
    • 1.2 CANReceiver类
      • 1.2.1 SimpleReceiver类
    • 1.3 Noise_node类
  • 二、CANMessageListener 接口
    • 2.1 IAT_Monitor
    • 2.2 BasicListener
    • 2.3 DLC_Monitor
  • 三、IATBitConverter 抽象类
    • 3.1 OneBitConverter类
    • 3.2 TwoBitConverter类
  • 四、ErrorCorrectionCode 错误纠正码接口
    • 4.1 SimpleCRC类
    • 4.2 SimpleParity

此篇文章是对原有代码的注释进行翻译,尝试对其架构和实现方式进行理解。

项目结构

在这里插入图片描述

Java实现代码

如图UML类图:
在这里插入图片描述
从图中明显可见,其代码组织方式,各个代码文件的继承和实现的关系。

以下内容围绕UML类图,分别进行阐述。

一、USBtin 基类

USBtin家族
在这里插入图片描述

  • USBtin是所有类的基类。
  • CANSender 和CANReceiver 是USBtin的派生类,同时增加了抽象方法,固也是抽象类,必须有下一级派生类才能使用。
    • SimpleSender 和 SimpleReceiver 分别是CANSender和CANReceiver抽象类的实现类。
  • Noice_node是USBtin的派生类。

USBtin类

USBtin类中,有9个成员变量,18个成员方法。

在这里插入图片描述

USBtin的代码:

package USBtin;

import jssc.*;

import java.util.ArrayList;
import java.util.LinkedList;

/**
 * 表示 USBtin.USBtin 设备.
 * 提供对USBtin.USBtin设备的虚拟访问
 * 串口.
 */
public class USBtin implements SerialPortEventListener {

    /** USBtin连接的串口(虚拟) */
    protected SerialPort serialPort;

    /** 从USBtin中获取的字符被收集在这个StringBuilder中。 */
    protected StringBuilder incomingMessage = new StringBuilder();

    /** CAN消息监听器 */
    protected ArrayList<CANMessageListener> listeners = new ArrayList<CANMessageListener>();

    /** 传播FIFO(先进先出)链表 */
    protected LinkedList<CANMessage> fifoTX = new LinkedList<CANMessage>();

    /** USBtin.USBtin 固件版本 */
    protected String firmwareVersion;

    /** USBtin.USBtin 硬件版本 */
    protected String hardwareVersion;

    /** USBtin.USBtin 序列号 */
    protected String serialNumber;

    /** USBtin.USBtin 的响应超时是1s */
    protected static final int TIMEOUT = 1000;

    /** CAN通道的打开模式 */
    public enum OpenMode {
        /** 在CAN总线上可发送可接收 */
        ACTIVE,
        /** 只能监听,不能发送 */
        LISTENONLY,
        /** 回送发送的CAN消息,断开物理CAN总线连接 */
        LOOPBACK
    }

    /**
     * 获取固件版本字符串.
     * 在 connect() 期间,从 USBtin.USBtin 请求固件版本.
     *
     * @return Firmware version
     */
    public String getFirmwareVersion() {
        return firmwareVersion;
    }

    /**
     * 获取硬件版本字符串.
     * 在 connect()期间,从 USBtin.USBtin 请求硬件版本. 
     *
     * @return Hardware version
     */
    public String getHardwareVersion() {
        return hardwareVersion;
    }

    /**
     * 获取序列号字符出串.
     * 在 connect()期间,从 USBtin.USBtin 请求序列号. 
     *
     * @return Serial number
     */
    public String getSerialNumber() {
        return serialNumber;
    }

    /**
     * 连接指定端口的USBtin.
     * 打开串口,清除挂起字符并发送关闭命令以确保处于配置模式.
     *
     * @param portName 虚拟串口名称
     * @throws USBtinException 连接USBtin.USBtin时可能出现的异常
     */
    public void connect(String portName) throws USBtinException {

        try {

            // 创建串口对象
            serialPort = new SerialPort(portName);

            // 打开串口并且初始化
            serialPort.openPort();
            serialPort.setParams(115200, 8, 1, 0);

            // 清除端口并确保我们处于配置模式(关闭命令)
            serialPort.writeBytes("\rC\r".getBytes());
            Thread.sleep(100);
            serialPort.purgePort(SerialPort.PURGE_RXCLEAR | SerialPort.PURGE_TXCLEAR);
            serialPort.writeBytes("C\r".getBytes());
            byte b;
            do {
                byte[] buffer = serialPort.readBytes(1, TIMEOUT);
                b = buffer[0];
            } while ((b != '\r') && (b != 7));

            // 获取版本信息
            this.firmwareVersion = this.transmit("v").substring(1);
            this.hardwareVersion = this.transmit("V").substring(1);
            this.serialNumber = this.transmit("N").substring(1);

            // 重置溢出的错误标志
            this.transmit("W2D00");

        } catch (SerialPortException e) {
            throw new USBtinException(e.getPortName() + " - " + e.getExceptionType());
        } catch (SerialPortTimeoutException e) {
            throw new USBtinException("Timeout! USBtin.USBtin doesn't answer. Right port?");
        } catch (InterruptedException e) {
            throw new USBtinException(e);
        }
    }

    /**
     * 断开连接.
     * 关闭串口连接
     *
     * @throws USBtinException 关闭连接时的异常
     */
    public void disconnect() throws USBtinException {

        try {
            serialPort.closePort();
        } catch (SerialPortException e) {
            throw new USBtinException(e.getExceptionType());
        }
    }

    /**
     * 打开CAN通道.
     * 给定模式下,设置波特率并打开CAN通道.
     *
     * @param baudrate 波特率(bit/s)
     * @param mode CAN总线访问模式
     * @throws USBtinException 打开CAN通道时的异常
     */
    public void openCANChannel(int baudrate, OpenMode mode) throws USBtinException {

        try {

            // 设置波特率
            char baudCh = ' ';
            switch (baudrate) {
                case 10000: baudCh = '0'; break;
                case 20000: baudCh = '1'; break;
                case 50000: baudCh = '2'; break;
                case 100000: baudCh = '3'; break;
                case 125000: baudCh = '4'; break;
                case 250000: baudCh = '5'; break;
                case 500000: baudCh = '6'; break;
                case 800000: baudCh = '7'; break;
                case 1000000: baudCh = '8'; break;
            }

            if (baudCh != ' ') {
                // 使用预设波特率
                this.transmit("S" + baudCh);
            } else {
                // 计算波特率寄存器设置
                final int FOSC = 24000000;
                int xdesired = FOSC / baudrate;
                int xopt = 0;
                int diffopt = 0;
                int brpopt = 0;

                // 遍历可能的位长度 (in TQ)
                for (int x = 11; x <= 23; x++) {

                    // 得到波特率因子的下一个偶数值
                    int xbrp = (xdesired * 10) / x;
                    int m = xbrp % 20;
                    if (m >= 10) xbrp += 20;
                    xbrp -= m;
                    xbrp /= 10;
                    // 范围检查
                    if (xbrp < 2) xbrp = 2;
                    if (xbrp > 128) xbrp = 128;
                    // 计算 diff
                    int xist = x * xbrp;
                    int diff = xdesired - xist;
                    if (diff < 0) diff = -diff;
                    // use this clock option if it is better than previous(使用这个时钟选项,如果它比以前更好)
                    if ((xopt == 0) || (diff <= diffopt)) { xopt = x; diffopt = diff; brpopt = xbrp / 2 - 1;};
                }

                // CNF寄存器值的映射
                int cnfvalues[] = {0x9203, 0x9303, 0x9B03, 0x9B04, 0x9C04, 0xA404, 0xA405, 0xAC05, 0xAC06, 0xAD06, 0xB506, 0xB507, 0xBD07};
                this.transmit("s" + String.format("%02x", brpopt | 0xC0) + String.format("%04x", cnfvalues[xopt - 11]));
                System.out.println("No preset for given baudrate " + baudrate + ". Set baudrate to " + (FOSC / ((brpopt + 1) * 2) / xopt));

            }

            // 打开CAN通道
            char modeCh;
            switch (mode) {
                default:
                    System.err.println("Mode " + mode + " not supported. Opening listen only.");
                case LISTENONLY: modeCh = 'L'; break;
                case LOOPBACK: modeCh = 'l'; break;
                case ACTIVE: modeCh = 'O'; break;
            }
            this.transmit(modeCh + "");

            // 注册串口事件监听器
            serialPort.setEventsMask(SerialPort.MASK_RXCHAR);
            serialPort.addEventListener(this);

        } catch (SerialPortException e) {
            throw new USBtinException(e);
        } catch (SerialPortTimeoutException e) {
            throw new USBtinException("Timeout! USBtin.USBtin doesn't answer. Right port?");
        }
    }

    /**
     * 关闭CAN通道.
     *
     * @throws USBtinException 关闭CAN通道时的异常
     */
    public void closeCANChannel() throws USBtinException {
        try {
            serialPort.removeEventListener();
            serialPort.writeBytes("C\r".getBytes());
        } catch (SerialPortException e) {
            throw new USBtinException(e.getExceptionType());
        }

        firmwareVersion = null;
        hardwareVersion = null;
    }

    /**
     * 从 USBtin.USBtin 读取响应
     *
     * @return Response from USBtin.USBtin
     * @throws SerialPortException Error while accessing USBtin.USBtin 访问异常
     * @throws SerialPortTimeoutException Timeout of serial port 超时异常
     */
    protected String readResponse() throws SerialPortException, SerialPortTimeoutException {
        StringBuilder response = new StringBuilder();
        while (true) {
            byte[] buffer = serialPort.readBytes(1, 1000);
            if (buffer[0] == '\r') {
                return response.toString();
            } else if (buffer[0] == 7) {
                throw new SerialPortException(serialPort.getPortName(), "transmit", "BELL signal");
            } else {
                response.append((char) buffer[0]);
            }
        }
    }

    /**
     * 将给定的命令发送到 USBtin
     *
     * @param cmd 命令
     * @return Response from USBtin.USBtin 来自USBtin的响应
     * @throws SerialPortException Error while talking to USBtin.USBtin
     * @throws SerialPortTimeoutException Timeout of serial port
     */
    public String transmit(String cmd) throws SerialPortException, SerialPortTimeoutException {

        String cmdline = cmd + "\r";
        serialPort.writeBytes(cmdline.getBytes());

        return this.readResponse();
    }


    /**
     * 处理串口事件.
     * 读取单个字节并检查结束符.
     * 如果到达行尾,解析命令并调度它.
     *
     * @param event Serial port event 串口事件
     */
    @Override
    public void serialEvent(SerialPortEvent event) {
        // 检查字节是否可用 (RX = bytes in input buffer)
        if (event.isRXCHAR() && event.getEventValue() > 0) {
            try {
                byte buffer[] = serialPort.readBytes();
                for (byte b : buffer) {
                    if ((b == '\r') && incomingMessage.length() > 0) {
                        String message = incomingMessage.toString();
                        char cmd = message.charAt(0);
                        // 检查是否为CAN消息
                        if (cmd == 't' || cmd == 'T' || cmd == 'r' || cmd == 'R') {
                            // 从消息字符串创建CAN消息
                            CANMessage canmsg = new CANMessage(message);
                            // 把CAN消息发送给监听器
                            for (CANMessageListener listener : listeners) {
                                listener.receiveCANMessage(canmsg);
                            }
                        } else if ((cmd == 'z') || (cmd == 'Z')) {
                            // 从发送fifo中删除第一条信息并发送下一条
                            fifoTX.removeFirst();
                            try {
                                sendFirstTXFifoMessage();
                            } catch (USBtinException ex) {
                                System.err.println(ex);
                            }
                        }
                        incomingMessage.setLength(0);
                    } else if (b == 0x07) {
                        // 从tx fifo重新发送第一个元素
                        try {
                            sendFirstTXFifoMessage();
                        } catch (USBtinException ex) {
                            System.err.println(ex);
                        }
                    } else if (b != '\r') {
                        incomingMessage.append((char) b);
                    }
                }
            } catch (SerialPortException ex) {
                System.err.println(ex);
            }
        }
    }

    /**
     * 添加消息监听器
     *
     * @param listener Listener object 监听器对象
     */
    public void addMessageListener(CANMessageListener listener) {
        listeners.add(listener);
    }

    /**
     * 移除消息监听器.
     *
     * @param listener Listener object 监听器对象
     */
    public void removeMessageListener(CANMessageListener listener) {
        listeners.remove(listener);
    }

    /**
     * 发送tx fifo中的第一个消息
     *
     * @throws USBtinException On serial port errors 串口错误异常
     */
    protected void sendFirstTXFifoMessage() throws USBtinException {

        if (fifoTX.size() == 0) {
            return;
        }

        CANMessage canmsg = fifoTX.getFirst();

        try {
            serialPort.writeBytes((canmsg.toString() + "\r").getBytes());
        } catch (SerialPortException e) {
            throw new USBtinException(e);
        }
    }

    /**
     * 发送指定CAN消息.
     *
     * @param canmsg Can message to send CAN消息
     * @throws USBtinException  On serial port errors
     */
    public void send(CANMessage canmsg) throws USBtinException {

        fifoTX.add(canmsg);

        if (fifoTX.size() > 1) return;

        sendFirstTXFifoMessage();
    }

    /**
     * 写入指定的MCP2515寄存器
     * 
     * @param register Register address 寄存器地址
     * @param value Value to write 写入值
     * @throws USBtinException On serial port errors 异常
     */
    public void writeMCPRegister(int register, byte value) throws USBtinException {

        try {
            String cmd = "W" + String.format("%02x", register) + String.format("%02x", value);
            transmit(cmd);
        } catch (SerialPortException e) {
            throw new USBtinException(e);
        } catch (SerialPortTimeoutException e) {
            throw new USBtinException("Timeout! USBtin.USBtin doesn't answer. Right port?");
        }
    }

    /**
     * 将指定的掩码寄存器写入MCP2515
     *
     * @param maskid Mask identifier (0 = RXM0, 1 = RXM1) 掩码标识符
     * @param registers Register values to write 要写入的寄存器值
     * @throws USBtinException On serial port errors 异常
     */
    protected void writeMCPFilterMaskRegisters(int maskid, byte[] registers) throws USBtinException {
        for (int i = 0; i < 4; i++) {
            writeMCPRegister(0x20 + maskid * 4 + i, registers[i]);
        }
    }

    /**
     * 将给定的滤波器寄存器写入MCP2515
     *
     * @param filterid Filter identifier (0 = RXF0, ... 5 = RXF5) 滤波器ID
     * @param registers Register values to write 要写入的寄存器值
     * @throws USBtinException On serial port errors 异常
     */
    protected void writeMCPFilterRegisters(int filterid, byte[] registers) throws USBtinException {

        int startregister[] = {0x00, 0x04, 0x08, 0x10, 0x14, 0x18};

        for (int i = 0; i < 4; i++) {
            writeMCPRegister(startregister[filterid] + i, registers[i]);
        }
    }

    /**
     * 设置硬件滤波器.
     * 调用这个函数的调用时机在 connect() 之后,openCANChannel()之前!
     *
     * @param fc 过滤器链(USBtin最多支持2个硬件过滤器链)
     * @throws USBtinException On serial port errors
     */
    public void setFilter(FilterChain[] fc) throws USBtinException {

        /*
         * MCP2515提供两个过滤器链。 每个链由一个掩码和一组过滤器组成:
         *
         * RXM0         RXM1
         *   |            |
         * RXF0         RXF2
         * RXF1         RXF3
         *              RXF4
         *              RXF5
         */

        // 如果没有指定过滤器链传入,则接收全部消息
        if ((fc == null) || (fc.length == 0)) {
            byte[] registers = {0, 0, 0, 0};
            writeMCPFilterMaskRegisters(0, registers);
            writeMCPFilterMaskRegisters(1, registers);
            return;
        }

        // 检查过滤器数量(范围)的最大值的大小
        if (fc.length > 2) {
            throw new USBtinException("Too many filter chains: " + fc.length + " (maximum is 2)!");
        }

        // 必要时交换通道,检查过滤器长度
        if (fc.length == 2) {
            if (fc[0].getFilters().length > fc[1].getFilters().length) {
                FilterChain temp = fc[0];
                fc[0] = fc[1];
                fc[1] = temp;
            }
            if ((fc[0].getFilters().length > 2) || (fc[1].getFilters().length > 4)) {
                throw new USBtinException("Filter chain too long: " + fc[0].getFilters().length + "/" + fc[1].getFilters().length + " (maximum is 2/4)!");
            }
        } else if (fc.length == 1) {
            if ((fc[0].getFilters().length > 4)) {
                throw new USBtinException("Filter chain too long: " + fc[0].getFilters().length + " (maximum is 4)!");
            }
        }

        // set MCP2515 filter/mask registers; walk through filter channels 设置MCP2515滤波器/掩码寄存器,遍历过滤通道
        int filterid = 0;
        int fcidx = 0;
        for (int channel = 0; channel < 2; channel++) {

            // set mask 设置掩码
            writeMCPFilterMaskRegisters(channel, fc[fcidx].getMask().getRegisters());

            // set filters 设置过滤器
            byte[] registers = {0, 0, 0, 0};
            for (int i = 0; i < (channel == 0 ? 2 : 4); i++) {
                if (fc[fcidx].getFilters().length > i) {
                    registers = fc[fcidx].getFilters()[i].getRegisters();
                }
                writeMCPFilterRegisters(filterid, registers);
                filterid++;
            }

            // 如果可用,转到下一个过滤器链
            if (fc.length - 1 > fcidx) {
                fcidx++;
            }
        }
    }
}

1.1 CANSender 类

CANSender 类是 USBtin 的派生类,新增2个抽象方法和1个普通方法。

在这里插入图片描述

//CANSender.java
package host_communication;  // 声明包名为host_communication

import USBtin.CANMessage;  // 导入USBtin包中的CANMessage类
import USBtin.USBtin;  // 导入USBtin包中的USBtin类
import USBtin.USBtinException;  // 导入USBtin包中的USBtinException类

public abstract class CANSender extends USBtin {  // 声明一个抽象类CANSender,继承自USBtin类

    public abstract CANMessage getMessageToSend();  // 声明一个抽象方法getMessageToSend,用于获取要发送的CAN消息

    public abstract void sendMessage(CANMessage message);  // 声明一个抽象方法sendMessage,用于发送CAN消息

    public void closedCC() {  // 声明一个方法closedCC,用于关闭CAN通道
        try {
            this.closeCANChannel();  // 尝试关闭CAN通道
            this.disconnect();  // 尝试断开连接
        } catch (USBtinException ex) {  // 捕获USBtinException异常
            ex.printStackTrace();  // 打印异常堆栈信息
        }
    }
}

1.1.1 SimpleSender类

CANSender 类是 CANSender(抽象类) 的派生类,实现了2个抽象方法。定义了1个成员变量和一个构造方法。

在这里插入图片描述

//SimpleSender.java
package host_communication;  // 声明包名为host_communication

import USBtin.CANMessage;  // 导入USBtin包中的CANMessage类
import USBtin.USBtin;  // 导入USBtin包中的USBtin类
import USBtin.USBtinException;  // 导入USBtin包中的USBtinException类

public class SimpleSender extends CANSender {  // 声明一个类SimpleSender,继承自CANSender类

    private CANMessage message;  // 声明一个私有的CANMessage类型的变量message

    public SimpleSender(CANMessage mess, String port, int channel) {  // 声明一个构造方法,接收CANMessage类型的mess、String类型的port和int类型的channel参数
        this.message = mess;  // 将mess赋值给message变量
        try {
            this.connect(port);  // 尝试连接指定的端口
            this.openCANChannel(channel, USBtin.OpenMode.ACTIVE);  // 尝试打开指定通道,并设置为活动模式
        } catch (USBtinException e) {  // 捕获USBtinException异常
            e.printStackTrace();  // 打印异常堆栈信息
        }
    }

    @Override
    public CANMessage getMessageToSend() {  // 实现抽象方法getMessageToSend,用于获取要发送的CAN消息
        return this.message;  // 返回message变量
    }

    @Override
    public void sendMessage(CANMessage message) {  // 实现抽象方法sendMessage,用于发送CAN消息
        try {
            this.send(message);  // 尝试发送消息
        } catch (USBtinException e) {  // 捕获USBtinException异常
            e.printStackTrace();  // 打印异常堆栈信息
        }
    }

}

1.2 CANReceiver类

CANReceiver 类是 USBtin 的派生类,新增1个普通方法。

package host_communication;

import USBtin.USBtin;
import USBtin.USBtinException;

public abstract class CANReceiver extends USBtin {

    public void closedCC() {
        try {
            this.closeCANChannel();
            this.disconnect();
        } catch (USBtinException ex) {
            ex.printStackTrace();
        }
    }

}

1.2.1 SimpleReceiver类

SimpleReceiver类是CANReceiver的派生类。定义了1个构造函数。

//SimpleReceiver.java
package host_communication;  //声明包名为host_communication

import USBtin.USBtinException;  // 导入USBtin包中的USBtinException类
import USBtin.USBtin;  // 导入USBtin包中的USBtin类

public class SimpleReceiver extends CANReceiver {  // 声明一个类SimpleReceiver,继承自CANReceiver类

    public SimpleReceiver(String port, int channel) {  // 声明一个构造方法,接收String类型的port和int类型的channel参数
        super();  // 调用父类的无参构造方法
        try {
            this.connect(port);  // 尝试连接指定的端口
            this.openCANChannel(channel, USBtin.OpenMode.ACTIVE);  // 尝试打开指定通道,并设置为活动模式
        } catch (USBtinException e) {  // 捕获USBtinException异常
            e.printStackTrace();  // 打印异常堆栈信息
        }
    }

}

1.3 Noise_node类

Noise_node类是USBtin的派生类。定义了2个成员变量和3个成员方法。

在这里插入图片描述

//Noise_node.java
package noise;  //声明包名为noise

import USBtin.CANMessage;  //导入USBtin包中的CANMessage类
import USBtin.USBtin;  //导入USBtin包中的USBtin类
import USBtin.USBtinException;  //导入USBtin包中的USBtinException类

public class Noise_node extends USBtin {  //声明一个类Noise_node,继承自USBtin类

    private long PERIOD;  //声明一个私有的long类型变量PERIOD
    private boolean running = true;  //声明一个私有的boolean类型变量running,并初始化为true

    public Noise_node(long period) {  //声明一个构造方法,接收一个long类型的period参数
        PERIOD = period;  //将period赋值给PERIOD变量
        if (PERIOD == 0) {  //如果PERIOD等于0
            running = false;  //将running设置为false
        }
    }

    public void start(CANMessage mess) {  //声明一个方法start,接收一个CANMessage类型的mess参数
        while (running) {  //当running为true时执行循环
            try {
                Thread.sleep((long) (PERIOD));  //线程休眠指定的时间
                this.send(mess);  //发送mess消息
            } catch (InterruptedException | USBtinException e) {  //捕获InterruptedException或USBtinException异常
                e.printStackTrace();  //打印异常堆栈信息
            }
        }
    }

    public void stop() {  //声明一个方法stop
        this.running = false;  //将running设置为false
    }
}

二、CANMessageListener 接口

CANMessageListener家族
在这里插入图片描述
CANMessageListener 接口具有3个实现类。

  1. IAT_Monitor类
  2. BasicListener类
  3. DLC_Monitor类

CANMessageListener 接口
在这里插入图片描述

CANMessageListener 接口代码

//CANMessageListener.java
package USBtin;

/**
 * CAN消息监听器.
 */
public interface CANMessageListener {

    /**
     * 方法在CAN消息传入时被调用
     *
     * @param canmsg 接收的CAN消息
     */
    public void receiveCANMessage(CANMessage canmsg);
}

2.1 IAT_Monitor

IAT_Monitor类是CANMessageListener接口的实现类。具有22个成员变量和6个成员函数。

在这里插入图片描述

代码:

// IAT_Monitor.java
package transmission_channel.IAT_channel;

import attestation.AttestationProtocol;
import USBtin.CANMessage;
import USBtin.CANMessageListener;
import error_detection.ErrorCorrectionCode;
import util.CANAuthMessage;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

public class IAT_Monitor implements CANMessageListener {

    private final int WINDOW_LENGTH;
    private final long PERIOD;
    private final long DELTA;
    private final long WATCH_ID;
    private final int CHANNEL;
    private final long NOISE_PERIOD;

    private long lastArrival;
    private List<Long> window = new LinkedList<>();
    private boolean detecting = false;
    private List<Byte> authMessage = new LinkedList<>();
    private FileWriter filewriterIAT;
    private FileWriter filewriterREL;
    private ErrorCorrectionCode corrector;
    private AttestationProtocol protocol;
    private long counter;
    private int silence_start;
    private int silence_end;
    private int silence_counter;
    private IATBitConverter converter;
    private boolean stopping;
    private boolean starting;
    private int total_received;

    public IAT_Monitor(long period, long delta, int windowLength, int watchid, int channel, long nperiod,
                       int silence_start, int silence_end, IATBitConverter converter) {
        this.PERIOD = period;
        this.DELTA = delta;
        this.WINDOW_LENGTH = windowLength;
        this.WATCH_ID = watchid;
        this.CHANNEL = channel;
        this.NOISE_PERIOD = nperiod;
        this.silence_start = silence_start;
        this.silence_end = silence_end;
        this.converter = converter;

        // 统计数据
        try {
	        // 创建文件夹
            new File("timings").mkdir();
            // 创建文件夹
            new File("reliability").mkdir();
            // 创建csv文件,filewriterIAT对象用于写入文件
            this.filewriterIAT = new FileWriter("timings/IAT_" + "P" + PERIOD + "_D" + DELTA + "_C" +
                    CHANNEL + "_N" + NOISE_PERIOD + ".csv");
            // this.filewriterREL = new FileWriter("reliability/IATrel_" + "_D" + DELTA + "_C" +
            //        CHANNEL + "_N" + NOISE_PERIOD + ".csv");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void receiveCANMessage(CANMessage message) {
        if (message.getId()==this.WATCH_ID) {
            this.counter += 1;
            long currentTime = System.currentTimeMillis();
            // 收到的第一条消息
            if (lastArrival == 0) {
                lastArrival = currentTime;
                window.add(PERIOD);
                return;
            }
            
            long IAT = currentTime - lastArrival;
            // 保存IAT
            try {
                this.filewriterIAT.append(IAT + ";" + System.currentTimeMillis() + "\n");
            } catch (IOException e) {
                e.printStackTrace();
            }

            lastArrival = currentTime;

            // sample running average 样本运行平均值
            window.add(IAT);
            if (window.size() == WINDOW_LENGTH) {
                detectBit(window);
                window = new LinkedList<>();
            }
        }
    }

    private String detectBit(List<Long> fullWindow) {

        long sum = 0L;
        for (long v : fullWindow) {
            sum += v;
        }
        long avg = sum / fullWindow.size();

        int intervals = this.converter.getIntervals(avg);

        if (intervals != 0) {
            if (starting) {
                //正确的(采取的)行为是开始的沉默位之后
                if (silence_counter >= silence_start) {
                    detecting = true;
                    starting = false;
                    silence_counter = 0;
                    this.authMessage.addAll(this.converter.convertFromIntervals(intervals));
                    return authMessage.toString();
                }
                else {
                    starting = false;
                    silence_counter = 0;
                    authMessage = new LinkedList<>();
                    return "Garbage bit";
                }
            }

            else if (stopping) {
                stopping = false;
                silence_counter = 0;
                this.authMessage = new LinkedList<>();
                return "Garbage bit";
            }

            // 正确行为:在检测过程中
            if (detecting) {
                this.authMessage.addAll(this.converter.convertFromIntervals(intervals));
                return this.authMessage.toString();
            }
        }

        else {
            silence_counter++;

            // Correct behaviour : start of start silence
            // 正确行为:开始沉默位时开始
            if (!starting && !detecting && !stopping) {
                starting = true;
                silence_counter = 1;
                authMessage = new LinkedList<>();
                return "Silence bit";
            }

            // Correct behaviour : start of end silence
            // 正确行为:结束沉默位时开始
            if (detecting) {
                detecting = false;
                stopping = true;
                silence_counter = 1;
            }
			
            if (stopping) {
                // Correct behaviour : end of end silence -> end of message
                // 正确行为:结束沉默位结束时 -> 消息结束
                if (silence_counter >= silence_end) {
                    stopping = false;
                    silence_counter = 0;

                    int attSize = authMessage.size();

                    // Check error detection
                    // 错误检测
                    if (this.corrector == null) {
                        System.out.println("DETECTED MESSAGE: " + authMessage);
                    }
                    else if (this.corrector.checkCodeForAuthMessage(authMessage)) {
                        List<Byte> mess = authMessage.subList(0, authMessage.size() - this.corrector.getNrCorrectingBits());
                        attSize = mess.size();
                        System.out.println("DETECTED MESSAGE: " + mess + " COUNTER: " + this.counter);
                    }
                    else {
//                        try {
//                            this.filewriterREL.append("O\n");
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }

                        System.out.println("Error in transmission detected! Received: " + authMessage + " COUNTER: " + counter);
                        this.authMessage = new LinkedList<>();
                        return "Silence bit";
                    }

                    // 检查认证
                    if (this.protocol != null) {
                        CANAuthMessage auth = new CANAuthMessage(authMessage.subList(0, attSize));
                        if (this.protocol.checkAttestationMessage(auth)) {
                            System.out.println("Attestation OK");
                            this.total_received++;

//                            try {
//                                this.filewriterREL.append("1\n");
//                            } catch (IOException e) {
//                                e.printStackTrace();
//                            }
                        }
                        else {
                            System.out.println("Attestation NOK");

//                            try {
//                                this.filewriterREL.append("O\n");
//                            } catch (IOException e) {
//                                e.printStackTrace();
//                            }
                        }
                    }
                    else {
                        this.total_received++;

//                        try {
//                            this.filewriterREL.append("1\n");
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
                    }

                    this.authMessage = new LinkedList<>();
                    return "Silence bit";
                }
            }
            return "Silence bit";
        }
        return "No bit detected";
    }

    public void setCorrector(ErrorCorrectionCode corrector) {
        this.corrector = corrector;
    }

    public void setProtocol(AttestationProtocol prot) {
        this.protocol = prot;
    }

    public void leave() {
        // 统计数据
        System.out.println("Total received: " + this.total_received);
        try {
            this.filewriterIAT.close();
            // this.filewriterREL.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

2.2 BasicListener

BasicListener类是CANMessageListener接口的实现类。实现了接口中的方法。

在这里插入图片描述
代码:

package util;

import USBtin.CANMessage;
import USBtin.CANMessageListener;

// 实现CANMessageListener接口的基本监听器类
public class BasicListener implements CANMessageListener {

    @Override
    public void receiveCANMessage(CANMessage canmsg) {
    	// 打印接收到的消息
        System.out.println("Watched message: " + canmsg.toString());
    }
}

2.3 DLC_Monitor

DLC_Monitor类是CANMessageListener接口的实现类。具有5个成员变量和5个成员函数。

在这里插入图片描述

代码:

// DLC_Monitor.java
package transmission_channel.DLC_channel;

import USBtin.CANMessage;
import USBtin.CANMessageListener;
import attestation.AttestationProtocol;
import error_detection.ErrorCorrectionCode;
import util.CANAuthMessage;

import java.util.LinkedList;
import java.util.List;

public class DLC_Monitor implements CANMessageListener {

    private boolean detecting = false; // 表示是否正在检测消息
    private List<Byte> authMessage = new LinkedList<>(); // 用于存储认证消息的列表
    private ErrorCorrectionCode corrector; // 错误校正码
    private AttestationProtocol protocol; // 认证协议
    private int WATCHID; // 监控的ID

    public DLC_Monitor(int watchid) {
        this.WATCHID = watchid; // 初始化监控的ID
    }

    @Override
    public void receiveCANMessage(CANMessage message) {
        detectBit(message); // 接收到CAN消息时调用detectBit方法进行处理
    }

    private void detectBit(CANMessage message) {
        if (message.getId() == this.WATCHID) { // 检查消息ID是否与监控的ID匹配

            int DLC = message.getDLC(); // 获取消息的数据长度码

            if (detecting) { // 如果正在检测消息
                if (DLC > 8) { // 如果数据长度码大于8
                    // 根据数据长度码的不同情况添加认证消息
                    switch (DLC) {
                        case (DLC_Node.DLC_0):
                            authMessage.add((byte) 0);
                            return;
                        case (DLC_Node.DLC_1):
                            authMessage.add((byte) 1);
                            return;
                        case (DLC_Node.DLC_00):
                            authMessage.add((byte) 0);
                            authMessage.add((byte) 0);
                            return;
                        case (DLC_Node.DLC_01):
                            authMessage.add((byte) 0);
                            authMessage.add((byte) 1);
                            return;
                        case (DLC_Node.DLC_10):
                            authMessage.add((byte) 1);
                            authMessage.add((byte) 0);
                            return;
                        case (DLC_Node.DLC_11):
                            authMessage.add((byte) 1);
                            authMessage.add((byte) 1);
                            return;
                    }
                }
            }

			// 如果数据长度码等于静默位的数据长度码
            if (DLC == DLC_Node.SILENCE_BIT_DLC) { 
	            // 如果正在检测消息
                if (detecting) { 
                    // 检查错误校正码
                    if (this.corrector == null) { // 如果没有设置错误校正码
                        System.out.println("DETECTED MESSAGE: " + authMessage); // 输出检测到的消息
                    } else if (this.corrector.checkCodeForAuthMessage(authMessage)) { // 如果校验通过
                        if (authMessage.size() - this.corrector.getNrCorrectingBits() < 0) {
                            System.out.println("Error in transmission detected! (too little bits)"); // 检测到传输错误(位数过少)
                        } else {
                            List<Byte> mess = authMessage.subList(0, authMessage.size() - this.corrector.getNrCorrectingBits());
                            System.out.println("DETECTED MESSAGE: " + mess); // 输出检测到的消息
                        }
                    } else {
                        System.out.println("Error in transmission detected! (wrong bits): " + authMessage); // 检测到传输错误(错误的位)
                    }

                    // 检查认证
                    int size = authMessage.size() - this.corrector.getNrCorrectingBits() > 0 ?
                            authMessage.size() - this.corrector.getNrCorrectingBits() :
                            0;
                    CANAuthMessage canAuthMessage = this.corrector == null ?
                            new CANAuthMessage(authMessage) :
                            new CANAuthMessage(authMessage.subList(0, size));

                    if (this.protocol.checkAttestationMessage(canAuthMessage)) {
                        System.out.println("Attestation OK"); // 认证通过
                    } else {
                        System.out.println("Attestation NOK"); // 认证不通过
                    }
                }
                authMessage = new LinkedList<>(); // 重置认证消息列表
                detecting = !detecting; // 切换检测状态
            }
        }
    }

    public void setCorrector(ErrorCorrectionCode corrector) {
        this.corrector = corrector; // 设置错误校正码
    }

    public void setAttestation(AttestationProtocol protocol) {
        this.protocol = protocol; // 设置认证协议
    }

}

三、IATBitConverter 抽象类

IATBitConverter类是一个抽象类。具有3个成员变量和7个成员方法(5个普通方法和2个抽象方法)。

在这里插入图片描述

package transmission_channel.IAT_channel;

import java.util.List;

// IAT位转换器的抽象类
public abstract class IATBitConverter {

    private long period; // 周期
    private long delta; // 增量
    private int bits; // 编码位数

    // 构造函数
    IATBitConverter(long period, long delta, int bits) {
        this.period = period; // 设置周期
        this.delta = delta; // 设置增量
        this.bits = bits; // 设置编码位数
    }

    // 根据IAT计算间隔数
    public int getIntervals(long IAT) {
        return Math.round(((float)(IAT-this.period))/(float)this.delta); // 计算间隔数
    }

    // 获取编码位数
    public int getBitsEncoded() {
        return this.bits; // 返回编码位数
    }

    // 从IAT转换为字节列表
    public List<Byte> convertFromIAT(long IAT) {
        return convertFromIntervals(getIntervals(IAT)); // 转换为间隔数后再转换为字节列表
    }

    // 从字节列表转换为IAT
    public long convertToIAT(List<Byte> bytes) {
        return this.period + this.delta*convertToIntervals(bytes); // 根据间隔数转换为IAT
    }

    // 抽象方法:根据间隔数转换为字节列表
    abstract List<Byte> convertFromIntervals(int intervals);

    // 抽象方法:根据字节列表转换为间隔数
    abstract int convertToIntervals(List<Byte> bytes);
}

3.1 OneBitConverter类

/*
 * OneBitConverter 扩展了IATBitConverter类,并提供了将间隔与字节相互转换的方法.
 */
package transmission_channel.IAT_channel;

import java.util.LinkedList;
import java.util.List;

public class OneBitConverter extends IATBitConverter {

    /*
     * 构造方法.
     * @param period The period.
     * @param delta The delta.
     * @param bits The number of bits.
     */
    public OneBitConverter(long period, long delta, int bits) {
        super(period, delta, bits);
    }

    /*
     * 间隔数转为字节列表
     * @param intervals The intervals to be converted.
     * @return A list of bytes.
     */
    @Override
    List<Byte> convertFromIntervals(int intervals) {
        List<Byte> result = new LinkedList<>();
        if (intervals == -1) { result.add( (byte) 0 ); }
        if (intervals == 1) { result.add( (byte) 1 ); }
        return result;
    }

    /*
     * 字节列表转换为间隔数.
     * @param bytes 要转换的字节列表.
     * @return The intervals .
     */
    @Override
    int convertToIntervals(List<Byte> bytes) {
        if (bytes.get(0) == ( (byte) 0) ) { return -1; }
        return 1;
    }
}

3.2 TwoBitConverter类

/*
 * TwoBitConverter 扩展了IATBitConverter类,并提供了将间隔与字节相互转换的方法。
 */
package transmission_channel.IAT_channel;

import java.util.LinkedList;
import java.util.List;

public class TwoBitConverter extends IATBitConverter {

    // 表示不同间隔的常量
    private final int INT_0 = 3;
    private final int INT_00 = 2;
    private final int INT_01 = 1;
    private final int INT_10 = -1;
    private final int INT_11 = -2;
    private final int INT_1 = -3;

    /*
     * 构造函数
     * @param period 周期
     * @param delta 增量.
     * @param bits 编码位数.
     */
    public TwoBitConverter(long period, long delta, int bits) {
        super(period, delta, bits);
    }

    /*
     * 间隔数转为字节列表.
     * @param intervals 间隔数.
     * @return A list of bytes.
     */
    @Override
    List<Byte> convertFromIntervals(int intervals) {
        List<Byte> result = new LinkedList<>();
        switch (intervals) {
            case (INT_0):
                result.add( (byte) 0 );
                break;
            case (INT_00):
                result.add( (byte) 0 );
                result.add( (byte) 0 );
                break;
            case (INT_01):
                result.add( (byte) 0 );
                result.add( (byte) 1 );
                break;
            case (INT_10):
                result.add( (byte) 1 );
                result.add( (byte) 0 );
                break;
            case (INT_11):
                result.add( (byte) 1 );
                result.add( (byte) 1 );
                break;
            case (INT_1):
                result.add( (byte) 1 );
                break;
        }
        return result;
    }

    /*
     * 间隔数转换为字节列表.
     * @param bytes 要转换的字节数.
     * @return The intervals.
     */
    @Override
    int convertToIntervals(List<Byte> bytes) {
        if (bytes.get(0).equals( (byte) 0 )) {
            if (bytes.size() == 1) { return INT_0; }
            if (bytes.get(1).equals( (byte) 0 )) { return INT_00; }
            return INT_01;
        }
        if (bytes.size() == 1) { return INT_1; }
        if (bytes.get(1).equals( (byte) 0 )) { return INT_10; }
        if (bytes.get(1).equals( (byte) 1 )) { return INT_11; }
        return 0;
    }

}

四、ErrorCorrectionCode 错误纠正码接口

/*
 * ErrorCorrectionCode 提供用于错误校正码的方法。
 */
package error_detection;

import util.CANAuthMessage; // 导入CANAuthMessage类
import java.util.List; // 导入List接口

public interface ErrorCorrectionCode {

    // 获取纠正位的数量
    int getNrCorrectingBits();

    // 获取CANAuthMessage的错误校正码
    List<Byte> getCodeForAuthMessage(CANAuthMessage message);

    // 检查CANAuthMessage的错误校正码
    boolean checkCodeForAuthMessage(List<Byte> message);
}

4.1 SimpleCRC类

/*
 * 这个类实现了ErrorCorrectionCode接口,用于简单的CRC(循环冗余校验)。
 */
public class SimpleCRC implements ErrorCorrectionCode {

    private int N; // 用于存储纠正位的数量
    private String polynomial = ""; // 用于存储多项式

    // 构造函数
    public SimpleCRC(int n, String polynomial) {
        // 如果n大于0且多项式的长度等于n+1,则进行初始化
        if (n > 0 && polynomial.length() == n+1) {
            this.N = n;
            this.polynomial = polynomial;
        }
    }

    // 获取纠正位的数量
    @Override
    public int getNrCorrectingBits() {
        return this.N;
    }

    // 获取CANAuthMessage的错误校正码
    @Override
    public List<Byte> getCodeForAuthMessage(CANAuthMessage message) {
        // 填充被除数
        String dividend = bytesToString(message.getMessage());
        for (int i=0; i<this.N; i++) { dividend += "0"; }

        String remainder = CRCdivision(dividend);

        return stringToBytes(remainder);
    }

    // 检查CANAuthMessage的错误校正码
    @Override
    public boolean checkCodeForAuthMessage(List<Byte> message) {
        if (message.size() < this.N*2) {
            return false;
        }

        String dividend = bytesToString(message);
        String remainder = CRCdivision(dividend);
        String wantedRemainder = "";
        for (int i=0; i<this.N; i++) { wantedRemainder += "0"; }

        return remainder.equals(wantedRemainder);
    }

    // CRC(循环冗余校验)的除法运算
    private String CRCdivision(String dividend) {
        String divisor = this.polynomial;
        while (divisor.length() < dividend.length()) { divisor += "0"; }
        String padded_divisor = divisor;

        while (dividend.contains("1") && dividend.indexOf("1")<dividend.length()-this.N) {
            // 对齐除数和被除数
            int offset = dividend.indexOf("1");
            divisor = padded_divisor;
            if (offset>0) { for (int i=0; i<offset; i++) { divisor = "0" + divisor; } }
            divisor = divisor.substring(0, dividend.length());

            // 执行除法
            String new_dividend = "";
            for (int i=0; i<dividend.length(); i++) {
                char d1 = dividend.charAt(i);
                char d2 = divisor.charAt(i);
                new_dividend += (d1 == d2) ? "0" : "1";
            }
            dividend = new_dividend;
        }

        // 提取最后N位(余数)
        return dividend.substring(dividend.length()-this.N);
    }

    // 将字节列表转换为字符串
    private String bytesToString(List<Byte> bytes) {
        String result = "";
        for (int i=0; i<bytes.size(); i++) {
            if (bytes.get(i).equals( (byte) 1 )) {
                result += "1";
            }
            else {
                result += "0";
            }
        }
        return result;
    }

    // 将字符串转换为字节列表
    private List<Byte> stringToBytes(String str) {
        List<Byte> result = new LinkedList<>();
        for (int i=0; i<str.length(); i++) {
            if (str.charAt(i) == '1') {
                result.add( (byte) 1 );
            }
            else {
                result.add( (byte) 0 );
            }
        }
        return result;
    }
}

4.2 SimpleParity

/*
 * 这个类实现了ErrorCorrectionCode接口,用于简单的奇偶校验。
 */
public class SimpleParity implements ErrorCorrectionCode {

    // 获取纠正位的数量
    @Override
    public int getNrCorrectingBits() {
        return 1;
    }

    // 获取CANAuthMessage的错误校正码
    @Override
    public List<Byte> getCodeForAuthMessage(CANAuthMessage message) {
        // 计算消息中1的个数
        int paritycounter = 0;
        for (int i=0 ; i<message.getMessage().size() ; i++) {
            if (message.getMessage().get(i) == ((byte) 1)) {
                paritycounter += 1;
            }
        }
        // 根据奇偶性添加校验位
        List<Byte> result = new LinkedList<Byte>();
        if (paritycounter%2 == 0) { result.add( (byte) 0 ); }
        else { result.add( (byte) 1 ); }
        return result;
    }

    // 检查CANAuthMessage的错误校正码
    @Override
    public boolean checkCodeForAuthMessage(List<Byte> message) {
        // 计算消息中1的个数
        int paritycounter = 0;
        for (int i=0 ; i<message.size() ; i++) {
            if (message.get(i).equals( (byte) 1 )) {
                paritycounter += 1;
            }
        }
        // 检查奇偶性
        return (paritycounter%2 == 0);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/340657.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Bit Extraction and Bootstrapping for BGV/BFV

参考文献&#xff1a; [GHS12] Gentry C, Halevi S, Smart N P. Better bootstrapping in fully homomorphic encryption[C]//International Workshop on Public Key Cryptography. Berlin, Heidelberg: Springer Berlin Heidelberg, 2012: 1-16.[AP13] Alperin-Sheriff J, Pe…

常见的嵌入式面试问题解答!

1.关键字static的作用是什么&#xff1f;为什么static变量只初始化一次&#xff1f; ​1&#xff09;修饰局部变量&#xff1a;使得变量变成静态变量&#xff0c;存储在静态区&#xff0c;存储在静态区的数据周期和程序相同&#xff0c; 在main函数开始前初始化&#xff0c;在…

【车载开发系列】AutoSar当中的诊断会话控制

【车载开发系列】AutoSar当中的诊断会话控制 【车载开发系列】AutoSar当中的诊断会话控制 【车载开发系列】AutoSar当中的诊断会话控制一. 什么是诊断会话控制服务二. 会话模式分类三. 会话的接口1&#xff09;获取当前会话状态2&#xff09;设置会话状态3&#xff09;返回默认…

分布式锁4 :数据库DB实现分布式锁的悲观锁和乐观锁,unique实现方式

一 方案1 使用悲观锁解决冲突 1.1 使用悲观锁原理 1.1.1 使用悲观锁的原理 1.悲观锁&#xff1a;在select的时候就会加锁&#xff0c;采用先加锁后处理的模式&#xff0c;虽然保证了数据处理的安全性&#xff0c;但也会阻塞其他线程的写操作。在读取数据时锁住那几行&…

UVT音乐证书考试时间确定,学习氛围渐浓

美国职业资格与人才管理中心&#xff08;UVT&#xff09;音乐证书考试时间正式确定&#xff0c;学习氛围逐渐浓厚。众多热爱音乐的从业者和学生开始积极备考&#xff0c;希望通过这一考试获得音乐领域的宝贵证书。音乐证书被认为是音乐人才展示个人专业水平的重要机会&#xff…

re:从0开始的HTML学习之路 2. HTML的标准结构说明

1. <DOCTYPE html> 文档声明&#xff0c;用于告诉浏览器&#xff0c;当前HTML文档采用的是什么版本。 必须写在当前HTML文档的首行&#xff08;可执行代码的首行&#xff09; HTML4的此标签与HTML5不同。 2. <html lang“en”> 根标签&#xff0c;整个HTML文档中…

虚拟机设置固定IP地址以及访问外网

一、虚拟机固定IP地址设置 1、IP地址查看命令 &#xff08;1&#xff09;ip a [rootlocalhost ~]# ip a • inet 192.168.93.129/24这表示该网络接口&#xff08;ens33&#xff09;被分配了一个IPv4地址是192.168.93.129&#xff0c;并且其子网掩码为 24位&#xff08;即/24…

Java多线程并发篇----第二十六篇

系列文章目录 文章目录 系列文章目录前言一、什么是 Executors 框架?二、什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者模型?三、什么是 Callable 和 Future?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分…

MySQL---多表等级查询综合练习

创建emp表 CREATE TABLE emp( empno INT(4) NOT NULL COMMENT 员工编号, ename VARCHAR(10) COMMENT 员工名字, job VARCHAR(10) COMMENT 职位, mgr INT(4) COMMENT 上司, hiredate DATE COMMENT 入职时间, sal INT(7) COMMENT 基本工资, comm INT(7) COMMENT 补贴, deptno INT…

大模型理论基础3

模型架构 模型概括 先把语言模型看成黑盒&#xff0c;以便于了解整体功能后拆分成&#xff1a;分词、模型架构 分词 首先要知道&#xff1a;语言模型 p 是建立在词元&#xff08;token&#xff09;序列的上的一个概率分布输出&#xff0c;其中每个词元来自某个词汇表V&#…

解决github无法访问的问题(修改hosts)

1.先ping github.com看是否能ping通 不能ping通的话&#xff0c;找到github最新的ip地址&#xff0c;修改hosts文件&#xff08;C:\Windows\System32\drivers\etc&#xff09; 找最新的ip地址的办法&#xff1a; a.cmd中ping时返回的 b.点击ipaddress.com查询网站链接 修改host…

微信小程序入门,学习全局配置与页面配置

目录 一、微信小程序 二、微信小程序的全局配置 三、微信小程序的页面配置 四、全局配置与页面配置的区别 一、微信小程序 微信小程序是一种基于微信平台的应用程序&#xff0c;它可以在微信内部直接运行&#xff0c;无需下载安装。微信小程序具有以下特点和优势&#xff…

数据结构与算法:图

文章目录 图1) 概念有向 vs 无向度权路径环图的连通性 2) 图的表示3) Java 表示4) DFS5) BFS6) 拓扑排序7) 最短路径DijkstraBellman-FordFloyd-Warshall 8) 最小生成树PrimKruskal 图 1) 概念 图是由顶点&#xff08;vertex&#xff09;和边&#xff08;edge&#xff09;组成…

前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验

前段时间写了一篇spring security的详细入门&#xff0c;但是没有联系实际。 所以这次在真实的项目中来演示一下怎样使用springsecurity来实现我们最常用的登录校验。本次演示使用现在市面上最常见的开发方式&#xff0c;前后端分离开发。前端使用vue3进行构建&#xff0c;用到…

vue生命周期图示

详见&#xff1a;官网介绍

梳理一下若依框架的权限过滤系统

梳理一下若依框架的权限过滤系统 首先&#xff0c;我们直入主题&#xff0c;且看这段代码 /*** 获取用户列表*/ PreAuthorize("ss.hasPermi(system:user:list)") GetMapping("/list") public TableDataInfo list(SysUser user) {startPage();List<SysU…

OpenHarmony当前进展和未来趋势

操作系统自20世纪50年代诞生&#xff0c;经历了从专用操作系统到通用操作系统的转变。整体可以将操作系统的发展历史分为3个阶段&#xff1a;PC时代、移动互联网时代、万物互联时代。 PC时代主要以计算机为主&#xff0c;用户规模从1970年的10亿增长到1990年的30亿。这一时代诞…

QComboBox 下拉框

文章目录 1、简介2、functions3、Signal QT 官方文档参考地址&#xff1a;https://doc.qt.io/qt-5/qcombobox.html 1、简介 QComboBox 是下拉列表框组件类&#xff0c;它提供一个下拉列表供用户选择&#xff0c;也可以直接当作一个 QLineEdit 用作输入。 2、functions 1、voi…

供应商导添加预扣税字段

文章目录 1 Introduction2 Code3 Summary 1 Introduction I only think I can assign value to them and I implement it by the following code . 2 Code LOOP AT gt_bukrs INTO gs_bukrs WHERE lifnr gs_alv1-lifnr.CLEAR:ls_company.ls_company-task M.ls_company-data…

mybatis----动态Sql

1.if标签 通过if标签构建动态条件&#xff0c;通过其test属性的true或false来判断该添加语句是否执行。 mapper接口 public interface AccountMapper {List<Account> selectAllByCondition(Account account); } 映射文件 <select id"selectAllByCondition&q…
最新文章