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

news2024/12/22 22:55:18

文章目录

  • 一、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.coloradmin.cn/o/1403527.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

swagger-ui配置错误原因

第一个问题 就是出现了error white page&#xff0c;主要是因为运行类的pom文件里没有添加到common类的地址dependency&#xff0c;导致出现问题&#xff0c;还到处排查 第二个问题 进去就跳出登录页面&#xff0c;可是我没有账户名和密码啊 在弄pom文件的时候不知道什么时候…

【idea】解决IDEA:The file size exceeds configured limit (5.12MB).

报错原因 The file size (5.13MB) exceeds configured limit (5.12MB). Code insight features are not available.(文件大小超出了设定值&#xff0c;IDEA不再对这个文件的进行代码解析了) 与之而来的结果是&#xff1a;IDEA中其他文件对于这个文件的所有引用都会报错&#x…

洛谷 P1126 机器人搬重物

题目描述 机器人移动学会&#xff08;RMI&#xff09;现在正尝试用机器人搬运物品。机器人的形状是一个直径 1.6 米的球。在试验阶段&#xff0c;机器人被用于在一个储藏室中搬运货物。储藏室是一个 NM 的网格&#xff0c;有些格子为不可移动的障碍。机器人的中心总是在格点上…

云原生DevOps基础与实战

一、DevOps基础 1、DevOps简介 DevOps 是一系列做法和工具&#xff0c;可以使 IT 和软件开发团队之间的流程实现自动化。其中&#xff0c;随着敏捷软件开发日趋流行&#xff0c;持续集成 (CI) 和持续交付 (CD) 已经成为该领域一个理想的解决方案。在 CI/CD 工作流中&#xff…

ARM 驱动 1.22

linux内核等待队列wait_queue_head_t 头文件 include <linux/wait.h> 定义并初始化 wait_queue_head_t r_wait; init_waitqueue_head(&cm_dev->r_wait); wait_queue_head_t 表示等待队列头&#xff0c;等待队列wait时&#xff0c;会导致进程或线程被休眠&…

最新版的Tuxera NTFS 2024 支持macOS 12系统

备受期待的Tuxera NTFS 2024 Mac中文版终于上线了&#xff0c;小编第一时间为您带来&#xff01;Tuxera NTFS 2024 中文版是一款非常好用的NTFS读写工具&#xff0c;可以让您完整的读写兼容NTFS格式驱动器&#xff0c;对磁盘进行访问、编辑、存储和传输文件等。同时还包括开源磁…

电脑存储位置不够怎么办

电脑内存不够怎么办&#xff01;&#xff01;&#xff01; 我前段时间经常因为电脑D盘内存不够而苦恼&#xff08;毕竟电脑内存就那么丁点&#xff0c;C盘作为系统盘不能随便下东西的情况下&#xff0c;就只能选择其他盘进 方法一&#xff1a;检查电脑硬盘的分区情况&#xf…

git内部原理

git内部原理 介绍目录结构说明 介绍 项目的本地仓库中&#xff0c;包含一个隐藏的.git目录&#xff0c;其不同的文件产生都源于git的各种不同命令造成&#xff0c;文件目录如下所示&#xff1a; 目录结构说明 上面最核心重要的为object目录&#xff0c;目录最主要有三个对象…

设置代码模板创建sql映射文件、Mybatis主配置文件

目录 1、Sql映射&#xff08;Sql Mapper&#xff09;文件的介绍 2、Mybatis的主配置文件的介绍 3、通过代码模板创建Sql映射文件 4、通过代码模板创建Mybatis主配置文件 1、Sql映射&#xff08;Sql Mapper&#xff09;文件的介绍 <?xml version"1.0" encod…

AI教我学编程之C#类的基本概念(1)

前言 在AI教我学编程之C#类型 中&#xff0c;我们学习了C#类型的的基础知识&#xff0c;而类正是类型的一种. 目录 区分类和类型 什么是类&#xff1f; 对话AI 追问 实操 追踪属性的使用 AI登场 逐步推进 提出疑问 药不能停 终于实现 探索事件的使用 异步/交互操作 耗时操…

全面分析vcomp140.dll丢失的修复方法,快速解决dll报错问题

vcomp140.dll文件的丢失可能会引发一系列系统运行和软件功能上的问题。作为Microsoft Visual C Redistributable Package的一部分&#xff0c;vcomp140.dll是一个至关重要的动态链接库文件&#xff0c;它的缺失可能导致某些应用程序无法正常启动或执行。具体来说&#xff0c;当…

今年想考CISP的一定要看完❗️

&#x1f3af;国家注册信息安全专业人员&#xff08;英文名称Certified Information Security Professional&#xff0c;简称“CISP"&#xff09;&#xff0c;是由中国信息安全测评中心于2002年推出的、业内公认的国内信息安全领域zqw的gj级认证&#xff0c;是国家对信息安…

【C++】list容器迭代器的模拟实现

list容器内部基本都是链表形式实现&#xff0c;这里的迭代器实现的逻辑需要注意C语言中指针的转换。 list容器如同数据结构中的队列&#xff0c;通常用链式结构进行存储。在这个容器中&#xff0c;我们可以模仿系统的逻辑&#xff0c;在头结点后设置一个“ 哨兵 ”&#xff0c;…

WPF多值转换器

背景&#xff1a;实现Slider拖动可以调整rgb 单转换器&#xff1a;WPF中数据绑定转换器Converter-CSDN博客 在View中&#xff1a; <StackPanel Orientation"Vertical"><Slider x:Name"slider_R" Minimum"0" Maximum"255" Wi…

阿里云优惠券领取入口、使用教程,2024优惠券更新

阿里云优惠代金券领取入口&#xff0c;阿里云服务器优惠代金券、域名代金券&#xff0c;在领券中心可以领取当前最新可用的满减代金券&#xff0c;阿里云百科aliyunbaike.com分享阿里云服务器代金券、领券中心、域名代金券领取、代金券查询及使用方法&#xff1a; 阿里云优惠券…

CentOS 7安装全解析:适合初学者的指导

目录 前言 一.centos安装 1.下载镜像文件 2.安装 二.远程连接&#xff0c;换源 1.下载并且使用MobaXtermMobaXterm free Xserver and tabbed SSH client for Windows (mobatek.net)https://mobaxterm.mobatek.net/ 远程连接 2.换源 前言 在当今的信息化时代&#xff0c…

SpikingJelly笔记之IFLIF神经元

文章目录 前言一、脉冲神经元二、IF神经元1、神经元模型2、神经元仿真 三、LIF神经元1、神经元模型2、神经元仿真 总结 前言 记录整合发放(integrate-and-fire, IF)神经元与漏电整合发放(leaky integrate-and-fire, LIF)神经元模型&#xff0c;以及在SpikingJelly中的实现方法…

mybatis----动态Sql

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

《文苑》文学艺术文化期刊投稿邮箱投稿方式

《文苑》杂志是国家新闻出版总署批准的正规期刊&#xff0c;本刊致力于中华优秀传统文化、文化旅游、文学艺术、哲学社会科学等方面的理论和实践研究&#xff0c;集理论性、艺术性、指导性于一体&#xff0c;是广大文化、哲学、社会科学工作者交流科研成果、传递学术思想的重要…

(蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)

能够表示为某个整数的平方的数字称为“平方数 虽然无法立即说出某个数是平方数&#xff0c;但经常可以断定某个数不是平方数。因为平方数的末位只可能是:0,1,4,5,6,9 这 6 个数字中的某个。所以&#xff0c;4325435332 必然不是平方数。 如果给你一个 2 位或 2 位以上的数字&am…