文章目录
- 一、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个实现类。
- IAT_Monitor类
- BasicListener类
- 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);
}
}