此篇文章是對(duì)原有代碼的注釋進(jìn)行翻譯,嘗試對(duì)其架構(gòu)和實(shí)現(xiàn)方式進(jìn)行理解。
項(xiàng)目結(jié)構(gòu)
Java實(shí)現(xiàn)代碼
如圖UML類圖:
從圖中明顯可見,其代碼組織方式,各個(gè)代碼文件的繼承和實(shí)現(xiàn)的關(guān)系。
以下內(nèi)容圍繞UML類圖,分別進(jìn)行闡述。
一、USBtin 基類
USBtin家族
- USBtin是所有類的基類。
- CANSender 和CANReceiver 是USBtin的派生類,同時(shí)增加了抽象方法,固也是抽象類,必須有下一級(jí)派生類才能使用。
- SimpleSender 和 SimpleReceiver 分別是CANSender和CANReceiver抽象類的實(shí)現(xiàn)類。
- Noice_node是USBtin的派生類。
USBtin類
USBtin類中,有9個(gè)成員變量,18個(gè)成員方法。
USBtin的代碼:
package USBtin;
import jssc.*;
import java.util.ArrayList;
import java.util.LinkedList;
/**
* 表示 USBtin.USBtin 設(shè)備.
* 提供對(duì)USBtin.USBtin設(shè)備的虛擬訪問
* 串口.
*/
public class USBtin implements SerialPortEventListener {
/** USBtin連接的串口(虛擬) */
protected SerialPort serialPort;
/** 從USBtin中獲取的字符被收集在這個(gè)StringBuilder中。 */
protected StringBuilder incomingMessage = new StringBuilder();
/** CAN消息監(jiān)聽器 */
protected ArrayList<CANMessageListener> listeners = new ArrayList<CANMessageListener>();
/** 傳播FIFO(先進(jìn)先出)鏈表 */
protected LinkedList<CANMessage> fifoTX = new LinkedList<CANMessage>();
/** USBtin.USBtin 固件版本 */
protected String firmwareVersion;
/** USBtin.USBtin 硬件版本 */
protected String hardwareVersion;
/** USBtin.USBtin 序列號(hào) */
protected String serialNumber;
/** USBtin.USBtin 的響應(yīng)超時(shí)是1s */
protected static final int TIMEOUT = 1000;
/** CAN通道的打開模式 */
public enum OpenMode {
/** 在CAN總線上可發(fā)送可接收 */
ACTIVE,
/** 只能監(jiān)聽,不能發(fā)送 */
LISTENONLY,
/** 回送發(fā)送的CAN消息,斷開物理CAN總線連接 */
LOOPBACK
}
/**
* 獲取固件版本字符串.
* 在 connect() 期間,從 USBtin.USBtin 請(qǐng)求固件版本.
*
* @return Firmware version
*/
public String getFirmwareVersion() {
return firmwareVersion;
}
/**
* 獲取硬件版本字符串.
* 在 connect()期間,從 USBtin.USBtin 請(qǐng)求硬件版本.
*
* @return Hardware version
*/
public String getHardwareVersion() {
return hardwareVersion;
}
/**
* 獲取序列號(hào)字符出串.
* 在 connect()期間,從 USBtin.USBtin 請(qǐng)求序列號(hào).
*
* @return Serial number
*/
public String getSerialNumber() {
return serialNumber;
}
/**
* 連接指定端口的USBtin.
* 打開串口,清除掛起字符并發(fā)送關(guān)閉命令以確保處于配置模式.
*
* @param portName 虛擬串口名稱
* @throws USBtinException 連接USBtin.USBtin時(shí)可能出現(xiàn)的異常
*/
public void connect(String portName) throws USBtinException {
try {
// 創(chuàng)建串口對(duì)象
serialPort = new SerialPort(portName);
// 打開串口并且初始化
serialPort.openPort();
serialPort.setParams(115200, 8, 1, 0);
// 清除端口并確保我們處于配置模式(關(guān)閉命令)
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);
// 重置溢出的錯(cuò)誤標(biāo)志
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);
}
}
/**
* 斷開連接.
* 關(guān)閉串口連接
*
* @throws USBtinException 關(guān)閉連接時(shí)的異常
*/
public void disconnect() throws USBtinException {
try {
serialPort.closePort();
} catch (SerialPortException e) {
throw new USBtinException(e.getExceptionType());
}
}
/**
* 打開CAN通道.
* 給定模式下,設(shè)置波特率并打開CAN通道.
*
* @param baudrate 波特率(bit/s)
* @param mode CAN總線訪問模式
* @throws USBtinException 打開CAN通道時(shí)的異常
*/
public void openCANChannel(int baudrate, OpenMode mode) throws USBtinException {
try {
// 設(shè)置波特率
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 != ' ') {
// 使用預(yù)設(shè)波特率
this.transmit("S" + baudCh);
} else {
// 計(jì)算波特率寄存器設(shè)置
final int FOSC = 24000000;
int xdesired = FOSC / baudrate;
int xopt = 0;
int diffopt = 0;
int brpopt = 0;
// 遍歷可能的位長(zhǎng)度 (in TQ)
for (int x = 11; x <= 23; x++) {
// 得到波特率因子的下一個(gè)偶數(shù)值
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;
// 計(jì)算 diff
int xist = x * xbrp;
int diff = xdesired - xist;
if (diff < 0) diff = -diff;
// use this clock option if it is better than previous(使用這個(gè)時(shí)鐘選項(xiàng),如果它比以前更好)
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 + "");
// 注冊(cè)串口事件監(jiān)聽器
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?");
}
}
/**
* 關(guān)閉CAN通道.
*
* @throws USBtinException 關(guān)閉CAN通道時(shí)的異常
*/
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 讀取響應(yīng)
*
* @return Response from USBtin.USBtin
* @throws SerialPortException Error while accessing USBtin.USBtin 訪問異常
* @throws SerialPortTimeoutException Timeout of serial port 超時(shí)異常
*/
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]);
}
}
}
/**
* 將給定的命令發(fā)送到 USBtin
*
* @param cmd 命令
* @return Response from USBtin.USBtin 來自USBtin的響應(yīng)
* @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();
}
/**
* 處理串口事件.
* 讀取單個(gè)字節(jié)并檢查結(jié)束符.
* 如果到達(dá)行尾,解析命令并調(diào)度它.
*
* @param event Serial port event 串口事件
*/
@Override
public void serialEvent(SerialPortEvent event) {
// 檢查字節(jié)是否可用 (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') {
// 從消息字符串創(chuàng)建CAN消息
CANMessage canmsg = new CANMessage(message);
// 把CAN消息發(fā)送給監(jiān)聽器
for (CANMessageListener listener : listeners) {
listener.receiveCANMessage(canmsg);
}
} else if ((cmd == 'z') || (cmd == 'Z')) {
// 從發(fā)送fifo中刪除第一條信息并發(fā)送下一條
fifoTX.removeFirst();
try {
sendFirstTXFifoMessage();
} catch (USBtinException ex) {
System.err.println(ex);
}
}
incomingMessage.setLength(0);
} else if (b == 0x07) {
// 從tx fifo重新發(fā)送第一個(gè)元素
try {
sendFirstTXFifoMessage();
} catch (USBtinException ex) {
System.err.println(ex);
}
} else if (b != '\r') {
incomingMessage.append((char) b);
}
}
} catch (SerialPortException ex) {
System.err.println(ex);
}
}
}
/**
* 添加消息監(jiān)聽器
*
* @param listener Listener object 監(jiān)聽器對(duì)象
*/
public void addMessageListener(CANMessageListener listener) {
listeners.add(listener);
}
/**
* 移除消息監(jiān)聽器.
*
* @param listener Listener object 監(jiān)聽器對(duì)象
*/
public void removeMessageListener(CANMessageListener listener) {
listeners.remove(listener);
}
/**
* 發(fā)送tx fifo中的第一個(gè)消息
*
* @throws USBtinException On serial port errors 串口錯(cuò)誤異常
*/
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);
}
}
/**
* 發(fā)送指定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) 掩碼標(biāo)識(shí)符
* @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]);
}
}
/**
* 設(shè)置硬件濾波器.
* 調(diào)用這個(gè)函數(shù)的調(diào)用時(shí)機(jī)在 connect() 之后,openCANChannel()之前!
*
* @param fc 過濾器鏈(USBtin最多支持2個(gè)硬件過濾器鏈)
* @throws USBtinException On serial port errors
*/
public void setFilter(FilterChain[] fc) throws USBtinException {
/*
* MCP2515提供兩個(gè)過濾器鏈。 每個(gè)鏈由一個(gè)掩碼和一組過濾器組成:
*
* 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;
}
// 檢查過濾器數(shù)量(范圍)的最大值的大小
if (fc.length > 2) {
throw new USBtinException("Too many filter chains: " + fc.length + " (maximum is 2)!");
}
// 必要時(shí)交換通道,檢查過濾器長(zhǎng)度
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 設(shè)置MCP2515濾波器/掩碼寄存器,遍歷過濾通道
int filterid = 0;
int fcidx = 0;
for (int channel = 0; channel < 2; channel++) {
// set mask 設(shè)置掩碼
writeMCPFilterMaskRegisters(channel, fc[fcidx].getMask().getRegisters());
// set filters 設(shè)置過濾器
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++;
}
// 如果可用,轉(zhuǎn)到下一個(gè)過濾器鏈
if (fc.length - 1 > fcidx) {
fcidx++;
}
}
}
}
1.1 CANSender 類
CANSender 類是 USBtin 的派生類,新增2個(gè)抽象方法和1個(gè)普通方法。
//CANSender.java
package host_communication; // 聲明包名為host_communication
import USBtin.CANMessage; // 導(dǎo)入U(xiǎn)SBtin包中的CANMessage類
import USBtin.USBtin; // 導(dǎo)入U(xiǎn)SBtin包中的USBtin類
import USBtin.USBtinException; // 導(dǎo)入U(xiǎn)SBtin包中的USBtinException類
public abstract class CANSender extends USBtin { // 聲明一個(gè)抽象類CANSender,繼承自USBtin類
public abstract CANMessage getMessageToSend(); // 聲明一個(gè)抽象方法getMessageToSend,用于獲取要發(fā)送的CAN消息
public abstract void sendMessage(CANMessage message); // 聲明一個(gè)抽象方法sendMessage,用于發(fā)送CAN消息
public void closedCC() { // 聲明一個(gè)方法closedCC,用于關(guān)閉CAN通道
try {
this.closeCANChannel(); // 嘗試關(guān)閉CAN通道
this.disconnect(); // 嘗試斷開連接
} catch (USBtinException ex) { // 捕獲USBtinException異常
ex.printStackTrace(); // 打印異常堆棧信息
}
}
}
1.1.1 SimpleSender類
CANSender 類是 CANSender(抽象類) 的派生類,實(shí)現(xiàn)了2個(gè)抽象方法。定義了1個(gè)成員變量和一個(gè)構(gòu)造方法。
//SimpleSender.java
package host_communication; // 聲明包名為host_communication
import USBtin.CANMessage; // 導(dǎo)入U(xiǎn)SBtin包中的CANMessage類
import USBtin.USBtin; // 導(dǎo)入U(xiǎn)SBtin包中的USBtin類
import USBtin.USBtinException; // 導(dǎo)入U(xiǎn)SBtin包中的USBtinException類
public class SimpleSender extends CANSender { // 聲明一個(gè)類SimpleSender,繼承自CANSender類
private CANMessage message; // 聲明一個(gè)私有的CANMessage類型的變量message
public SimpleSender(CANMessage mess, String port, int channel) { // 聲明一個(gè)構(gòu)造方法,接收CANMessage類型的mess、String類型的port和int類型的channel參數(shù)
this.message = mess; // 將mess賦值給message變量
try {
this.connect(port); // 嘗試連接指定的端口
this.openCANChannel(channel, USBtin.OpenMode.ACTIVE); // 嘗試打開指定通道,并設(shè)置為活動(dòng)模式
} catch (USBtinException e) { // 捕獲USBtinException異常
e.printStackTrace(); // 打印異常堆棧信息
}
}
@Override
public CANMessage getMessageToSend() { // 實(shí)現(xiàn)抽象方法getMessageToSend,用于獲取要發(fā)送的CAN消息
return this.message; // 返回message變量
}
@Override
public void sendMessage(CANMessage message) { // 實(shí)現(xiàn)抽象方法sendMessage,用于發(fā)送CAN消息
try {
this.send(message); // 嘗試發(fā)送消息
} catch (USBtinException e) { // 捕獲USBtinException異常
e.printStackTrace(); // 打印異常堆棧信息
}
}
}
1.2 CANReceiver類
CANReceiver 類是 USBtin 的派生類,新增1個(gè)普通方法。
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個(gè)構(gòu)造函數(shù)。
//SimpleReceiver.java
package host_communication; //聲明包名為host_communication
import USBtin.USBtinException; // 導(dǎo)入U(xiǎn)SBtin包中的USBtinException類
import USBtin.USBtin; // 導(dǎo)入U(xiǎn)SBtin包中的USBtin類
public class SimpleReceiver extends CANReceiver { // 聲明一個(gè)類SimpleReceiver,繼承自CANReceiver類
public SimpleReceiver(String port, int channel) { // 聲明一個(gè)構(gòu)造方法,接收String類型的port和int類型的channel參數(shù)
super(); // 調(diào)用父類的無參構(gòu)造方法
try {
this.connect(port); // 嘗試連接指定的端口
this.openCANChannel(channel, USBtin.OpenMode.ACTIVE); // 嘗試打開指定通道,并設(shè)置為活動(dòng)模式
} catch (USBtinException e) { // 捕獲USBtinException異常
e.printStackTrace(); // 打印異常堆棧信息
}
}
}
1.3 Noise_node類
Noise_node類是USBtin的派生類。定義了2個(gè)成員變量和3個(gè)成員方法。
//Noise_node.java
package noise; //聲明包名為noise
import USBtin.CANMessage; //導(dǎo)入U(xiǎn)SBtin包中的CANMessage類
import USBtin.USBtin; //導(dǎo)入U(xiǎn)SBtin包中的USBtin類
import USBtin.USBtinException; //導(dǎo)入U(xiǎn)SBtin包中的USBtinException類
public class Noise_node extends USBtin { //聲明一個(gè)類Noise_node,繼承自USBtin類
private long PERIOD; //聲明一個(gè)私有的long類型變量PERIOD
private boolean running = true; //聲明一個(gè)私有的boolean類型變量running,并初始化為true
public Noise_node(long period) { //聲明一個(gè)構(gòu)造方法,接收一個(gè)long類型的period參數(shù)
PERIOD = period; //將period賦值給PERIOD變量
if (PERIOD == 0) { //如果PERIOD等于0
running = false; //將running設(shè)置為false
}
}
public void start(CANMessage mess) { //聲明一個(gè)方法start,接收一個(gè)CANMessage類型的mess參數(shù)
while (running) { //當(dāng)running為true時(shí)執(zhí)行循環(huán)
try {
Thread.sleep((long) (PERIOD)); //線程休眠指定的時(shí)間
this.send(mess); //發(fā)送mess消息
} catch (InterruptedException | USBtinException e) { //捕獲InterruptedException或USBtinException異常
e.printStackTrace(); //打印異常堆棧信息
}
}
}
public void stop() { //聲明一個(gè)方法stop
this.running = false; //將running設(shè)置為false
}
}
二、CANMessageListener 接口
CANMessageListener家族
CANMessageListener 接口具有3個(gè)實(shí)現(xiàn)類。
- IAT_Monitor類
- BasicListener類
- DLC_Monitor類
CANMessageListener 接口
CANMessageListener 接口代碼
//CANMessageListener.java
package USBtin;
/**
* CAN消息監(jiān)聽器.
*/
public interface CANMessageListener {
/**
* 方法在CAN消息傳入時(shí)被調(diào)用
*
* @param canmsg 接收的CAN消息
*/
public void receiveCANMessage(CANMessage canmsg);
}
2.1 IAT_Monitor
IAT_Monitor類是CANMessageListener接口的實(shí)現(xiàn)類。具有22個(gè)成員變量和6個(gè)成員函數(shù)。
代碼:
// 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;
// 統(tǒng)計(jì)數(shù)據(jù)
try {
// 創(chuàng)建文件夾
new File("timings").mkdir();
// 創(chuàng)建文件夾
new File("reliability").mkdir();
// 創(chuàng)建csv文件,filewriterIAT對(duì)象用于寫入文件
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 樣本運(yùn)行平均值
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";
}
// 正確行為:在檢測(cè)過程中
if (detecting) {
this.authMessage.addAll(this.converter.convertFromIntervals(intervals));
return this.authMessage.toString();
}
}
else {
silence_counter++;
// Correct behaviour : start of start silence
// 正確行為:開始沉默位時(shí)開始
if (!starting && !detecting && !stopping) {
starting = true;
silence_counter = 1;
authMessage = new LinkedList<>();
return "Silence bit";
}
// Correct behaviour : start of end silence
// 正確行為:結(jié)束沉默位時(shí)開始
if (detecting) {
detecting = false;
stopping = true;
silence_counter = 1;
}
if (stopping) {
// Correct behaviour : end of end silence -> end of message
// 正確行為:結(jié)束沉默位結(jié)束時(shí) -> 消息結(jié)束
if (silence_counter >= silence_end) {
stopping = false;
silence_counter = 0;
int attSize = authMessage.size();
// Check error detection
// 錯(cuò)誤檢測(cè)
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";
}
// 檢查認(rèn)證
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() {
// 統(tǒng)計(jì)數(shù)據(jù)
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接口的實(shí)現(xiàn)類。實(shí)現(xiàn)了接口中的方法。
代碼:
package util;
import USBtin.CANMessage;
import USBtin.CANMessageListener;
// 實(shí)現(xiàn)CANMessageListener接口的基本監(jiān)聽器類
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接口的實(shí)現(xiàn)類。具有5個(gè)成員變量和5個(gè)成員函數(shù)。
代碼:
// 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; // 表示是否正在檢測(cè)消息
private List<Byte> authMessage = new LinkedList<>(); // 用于存儲(chǔ)認(rèn)證消息的列表
private ErrorCorrectionCode corrector; // 錯(cuò)誤校正碼
private AttestationProtocol protocol; // 認(rèn)證協(xié)議
private int WATCHID; // 監(jiān)控的ID
public DLC_Monitor(int watchid) {
this.WATCHID = watchid; // 初始化監(jiān)控的ID
}
@Override
public void receiveCANMessage(CANMessage message) {
detectBit(message); // 接收到CAN消息時(shí)調(diào)用detectBit方法進(jìn)行處理
}
private void detectBit(CANMessage message) {
if (message.getId() == this.WATCHID) { // 檢查消息ID是否與監(jiān)控的ID匹配
int DLC = message.getDLC(); // 獲取消息的數(shù)據(jù)長(zhǎng)度碼
if (detecting) { // 如果正在檢測(cè)消息
if (DLC > 8) { // 如果數(shù)據(jù)長(zhǎng)度碼大于8
// 根據(jù)數(shù)據(jù)長(zhǎng)度碼的不同情況添加認(rèn)證消息
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;
}
}
}
// 如果數(shù)據(jù)長(zhǎng)度碼等于靜默位的數(shù)據(jù)長(zhǎng)度碼
if (DLC == DLC_Node.SILENCE_BIT_DLC) {
// 如果正在檢測(cè)消息
if (detecting) {
// 檢查錯(cuò)誤校正碼
if (this.corrector == null) { // 如果沒有設(shè)置錯(cuò)誤校正碼
System.out.println("DETECTED MESSAGE: " + authMessage); // 輸出檢測(cè)到的消息
} else if (this.corrector.checkCodeForAuthMessage(authMessage)) { // 如果校驗(yàn)通過
if (authMessage.size() - this.corrector.getNrCorrectingBits() < 0) {
System.out.println("Error in transmission detected! (too little bits)"); // 檢測(cè)到傳輸錯(cuò)誤(位數(shù)過少)
} else {
List<Byte> mess = authMessage.subList(0, authMessage.size() - this.corrector.getNrCorrectingBits());
System.out.println("DETECTED MESSAGE: " + mess); // 輸出檢測(cè)到的消息
}
} else {
System.out.println("Error in transmission detected! (wrong bits): " + authMessage); // 檢測(cè)到傳輸錯(cuò)誤(錯(cuò)誤的位)
}
// 檢查認(rèn)證
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"); // 認(rèn)證通過
} else {
System.out.println("Attestation NOK"); // 認(rèn)證不通過
}
}
authMessage = new LinkedList<>(); // 重置認(rèn)證消息列表
detecting = !detecting; // 切換檢測(cè)狀態(tài)
}
}
}
public void setCorrector(ErrorCorrectionCode corrector) {
this.corrector = corrector; // 設(shè)置錯(cuò)誤校正碼
}
public void setAttestation(AttestationProtocol protocol) {
this.protocol = protocol; // 設(shè)置認(rèn)證協(xié)議
}
}
三、IATBitConverter 抽象類
IATBitConverter類是一個(gè)抽象類。具有3個(gè)成員變量和7個(gè)成員方法(5個(gè)普通方法和2個(gè)抽象方法)。文章來源:http://www.zghlxwxcb.cn/news/detail-819919.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-819919.html
package transmission_channel.IAT_channel;
import java.util.List;
// IAT位轉(zhuǎn)換器的抽象類
public abstract class IATBitConverter {
private long period; // 周期
private long delta; // 增量
private int bits; // 編碼位數(shù)
// 構(gòu)造函數(shù)
IATBitConverter(long period, long delta, int bits) {
this.period = period; // 設(shè)置周期
this.delta = delta; // 設(shè)置增量
this.bits = bits; // 設(shè)置編碼位數(shù)
}
// 根據(jù)IAT計(jì)算間隔數(shù)
public int getIntervals(long IAT) {
return Math.round(((float)(IAT-this.period))/(float)this.delta); // 計(jì)算間隔數(shù)
}
// 獲取編碼位數(shù)
public int getBitsEncoded() {
return this.bits; // 返回編碼位數(shù)
}
// 從IAT轉(zhuǎn)換為字節(jié)列表
public List<Byte> convertFromIAT(long IAT) {
return convertFromIntervals(getIntervals(IAT)); // 轉(zhuǎn)換為間隔數(shù)后再轉(zhuǎn)換為字節(jié)列表
}
// 從字節(jié)列表轉(zhuǎn)換為IAT
public long convertToIAT(List<Byte> bytes) {
return this.period + this.delta*convertToIntervals(bytes); // 根據(jù)間隔數(shù)轉(zhuǎn)換為IAT
}
// 抽象方法:根據(jù)間隔數(shù)轉(zhuǎn)換為字節(jié)列表
abstract List<Byte> convertFromIntervals(int intervals);
// 抽象方法:根據(jù)字節(jié)列表轉(zhuǎn)換為間隔數(shù)
abstract int convertToIntervals(List<Byte> bytes);
}
3.1 OneBitConverter類
/*
* OneBitConverter 擴(kuò)展了IATBitConverter類,并提供了將間隔與字節(jié)相互轉(zhuǎn)換的方法.
*/
package transmission_channel.IAT_channel;
import java.util.LinkedList;
import java.util.List;
public class OneBitConverter extends IATBitConverter {
/*
* 構(gòu)造方法.
* @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);
}
/*
* 間隔數(shù)轉(zhuǎn)為字節(jié)列表
* @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;
}
/*
* 字節(jié)列表轉(zhuǎn)換為間隔數(shù).
* @param bytes 要轉(zhuǎn)換的字節(jié)列表.
* @return The intervals .
*/
@Override
int convertToIntervals(List<Byte> bytes) {
if (bytes.get(0) == ( (byte) 0) ) { return -1; }
return 1;
}
}
3.2 TwoBitConverter類
/*
* TwoBitConverter 擴(kuò)展了IATBitConverter類,并提供了將間隔與字節(jié)相互轉(zhuǎn)換的方法。
*/
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;
/*
* 構(gòu)造函數(shù)
* @param period 周期
* @param delta 增量.
* @param bits 編碼位數(shù).
*/
public TwoBitConverter(long period, long delta, int bits) {
super(period, delta, bits);
}
/*
* 間隔數(shù)轉(zhuǎn)為字節(jié)列表.
* @param intervals 間隔數(shù).
* @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;
}
/*
* 間隔數(shù)轉(zhuǎn)換為字節(jié)列表.
* @param bytes 要轉(zhuǎn)換的字節(jié)數(shù).
* @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 錯(cuò)誤糾正碼接口
/*
* ErrorCorrectionCode 提供用于錯(cuò)誤校正碼的方法。
*/
package error_detection;
import util.CANAuthMessage; // 導(dǎo)入CANAuthMessage類
import java.util.List; // 導(dǎo)入List接口
public interface ErrorCorrectionCode {
// 獲取糾正位的數(shù)量
int getNrCorrectingBits();
// 獲取CANAuthMessage的錯(cuò)誤校正碼
List<Byte> getCodeForAuthMessage(CANAuthMessage message);
// 檢查CANAuthMessage的錯(cuò)誤校正碼
boolean checkCodeForAuthMessage(List<Byte> message);
}
4.1 SimpleCRC類
/*
* 這個(gè)類實(shí)現(xiàn)了ErrorCorrectionCode接口,用于簡(jiǎn)單的CRC(循環(huán)冗余校驗(yàn))。
*/
public class SimpleCRC implements ErrorCorrectionCode {
private int N; // 用于存儲(chǔ)糾正位的數(shù)量
private String polynomial = ""; // 用于存儲(chǔ)多項(xiàng)式
// 構(gòu)造函數(shù)
public SimpleCRC(int n, String polynomial) {
// 如果n大于0且多項(xiàng)式的長(zhǎng)度等于n+1,則進(jìn)行初始化
if (n > 0 && polynomial.length() == n+1) {
this.N = n;
this.polynomial = polynomial;
}
}
// 獲取糾正位的數(shù)量
@Override
public int getNrCorrectingBits() {
return this.N;
}
// 獲取CANAuthMessage的錯(cuò)誤校正碼
@Override
public List<Byte> getCodeForAuthMessage(CANAuthMessage message) {
// 填充被除數(shù)
String dividend = bytesToString(message.getMessage());
for (int i=0; i<this.N; i++) { dividend += "0"; }
String remainder = CRCdivision(dividend);
return stringToBytes(remainder);
}
// 檢查CANAuthMessage的錯(cuò)誤校正碼
@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(循環(huán)冗余校驗(yàn))的除法運(yùn)算
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) {
// 對(duì)齊除數(shù)和被除數(shù)
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());
// 執(zhí)行除法
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位(余數(shù))
return dividend.substring(dividend.length()-this.N);
}
// 將字節(jié)列表轉(zhuǎ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;
}
// 將字符串轉(zhuǎn)換為字節(jié)列表
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
/*
* 這個(gè)類實(shí)現(xiàn)了ErrorCorrectionCode接口,用于簡(jiǎn)單的奇偶校驗(yàn)。
*/
public class SimpleParity implements ErrorCorrectionCode {
// 獲取糾正位的數(shù)量
@Override
public int getNrCorrectingBits() {
return 1;
}
// 獲取CANAuthMessage的錯(cuò)誤校正碼
@Override
public List<Byte> getCodeForAuthMessage(CANAuthMessage message) {
// 計(jì)算消息中1的個(gè)數(shù)
int paritycounter = 0;
for (int i=0 ; i<message.getMessage().size() ; i++) {
if (message.getMessage().get(i) == ((byte) 1)) {
paritycounter += 1;
}
}
// 根據(jù)奇偶性添加校驗(yàn)位
List<Byte> result = new LinkedList<Byte>();
if (paritycounter%2 == 0) { result.add( (byte) 0 ); }
else { result.add( (byte) 1 ); }
return result;
}
// 檢查CANAuthMessage的錯(cuò)誤校正碼
@Override
public boolean checkCodeForAuthMessage(List<Byte> message) {
// 計(jì)算消息中1的個(gè)數(shù)
int paritycounter = 0;
for (int i=0 ; i<message.size() ; i++) {
if (message.get(i).equals( (byte) 1 )) {
paritycounter += 1;
}
}
// 檢查奇偶性
return (paritycounter%2 == 0);
}
}
到了這里,關(guān)于【論文代碼】基于隱蔽帶寬的汽車控制網(wǎng)路魯棒認(rèn)證-到達(dá)時(shí)間間隔通道的Java實(shí)現(xiàn)(一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!