一个周期(两两一组)内必是跳转电平(01或10)
- 1:
10
- 0:
01
两位起始位:
10
编码
两位结束位:
00
每bit解码再组合
- 10:1
- 01:0
各种干扰和多设备同时发送可能会使收到的编码错误。
在判断编码数据是否正确时,我们需要检查每组数据(每两位)是否符合曼切斯特编码规则(1表示为10,0表示为01)。
正确案例:
原始数据:
1101
曼彻斯特编码:
10 10 01 10
信息块(起始+编码+结束):
10 10 10 01 10 00
错误案例:
编码:
10 10 11 01
判断:第3组(11)不符合曼彻斯特编码规则。
编码:
10 10 11 10
判断:第3组(11)不符合曼彻斯特编码规则。
编码:
10 10 00 10
判断:第3组(00)不符合曼彻斯特编码规则。
对编码部分解码即NRZ
码值
曼彻斯特码读入串(信息块):
10 10 01 01 10 01 00
去除起始位和结束位:
10 01 01 10 01
NRZ
(解码):10010
跳转与前一个的编码有关。编码规则与原数据有关,跳变即0->1或1->0
每个数字被编码为一个字节,第一个是起始位置,后一个为中间位置。
两位起始位:
10
编码
两位结束位:
00
每bit解码再组合。密勒码解码有两种。
10或01:1
11或00:0
原数据:
10110010
编码[假设开始时
bit (i-1)=1
(与第一个数相同)]:注意看表规则
- 原数据第一位是1,根据表格前一位不需要,而
bit(i-1)
是1,起始位不跳转还是1
,中间位跳转是0
,则第一位编码为10
- 原数据第二位是0,前一位是1,根据前一位的编码(10)末尾0,此时的
bit(i-1)
更新为0,根据编码规则,起始位不跳转还是0
,中间位不跳转是0
,则第二位编码为00
- 原数据第三位是1,根据表格前一位不需要,根据前一位的编码(00)末尾0,此时的
bit(i-1)
为0,起始位不跳转还是0
,中间位0跳转是1
,则第三位编码为01
- 其余同理….…
- 原数据最后一位是0,前一位是1,根据前一位的编码(10)末尾0,此时的
bit(i-1)
为0,起始位不跳转还是0
,中间位不跳转是0
,则最后一位编码为00
编码结果:
10 00 01 10 00 11 10 00
即下方图片:
对编码部分解码即NRZ
码值
密勒码读入串(信息块):
10 00 01 10 00 11 10 00
去除起始位和结束位:
00 01 10 00 11 10
NRZ
(解码):011001
点此查看CRC详细内容
注意多项式和信息码的转换
如: M ( X ) = X 6 + X 4 + x 3 + 1 M(X)=X^6+X^4+x^3+1 M(X)=X6+X4+x3+1即 1 ∗ X 6 + 0 ∗ X 5 + 1 ∗ X 4 + 1 ∗ x 3 + 0 ∗ X 2 + 0 ∗ X 1 + 1 ∗ X 0 1*X^6+0*X^5+1*X^4+1*x^3+0*X^2+0*X^1+1*X^0 1∗X6+0∗X5+1∗X4+1∗x3+0∗X2+0∗X1+1∗X0
则信息码为系数:1011001
根据多项式 M ( X ) M(X) M(X),得到K位信息码A
根据多项式 G ( X ) G(X) G(X),得到r位信息码B
在信息码A后面附加r-1个0,得到信息码C,保证总位数为k + r
用模2除法(异或)计算:信息码C/信息码B,余数即校验码
结果:信息码A+校验码有效位
校验码有效位:一般去除前缀0即可,有效位满足k+r,不足再往前补0,长度一般为
r-1
k-1阶多项式 M ( X ) = X 6 + X 4 + x 3 + 1 M(X)=X^6+X^4+x^3+1 M(X)=X6+X4+x3+1,则信息码A为:
1011001
r阶生成多项式 G ( X ) = X 4 + X 3 + 1 G(X)=X^4+X^3+1 G(X)=X4+X3+1,信息码B:
11001
则信息码C:
10110010000
计算(注意每次都是非0左对齐)
点此查看ALOHA详细内容
发送时间没有冲突,都可以发送成功。
发生冲突: ∣ 发送时间 1 − 发送时间 2 ∣ < 帧长 ( 用时间描述 ) ∣ 发送时间 1 − 发送时间 2 ∣ < 帧长 ( 用时间描述 ) ∣发送时间1−发送时间2∣<帧长(用时间描述)
S = G e − 2 G S=Ge^{-2G} S=Ge−2G
G为帧产生率,当G=0.5时, S m a x = 1 / ( 2 e ) = 18.4 % S_{max}=1/(2e)=18.4\% Smax=1/(2e)=18.4%
P = S / G = e − 2 G P=S/G=e^{-2G} P=S/G=e−2G
帧时越长,G越大,成功率越低
发送时间没有冲突,都可以发送成功。
发生冲突:两个终端发送帧的时间相同
S = G e − 2 G S=Ge^{-2G} S=Ge−2G
G为帧产生率,当G=1时, S m a x = 1 / e = 36.8 % S_{max}=1/e=36.8\% Smax=1/e=36.8%,是纯Aloha的两倍
P = S / G = e − 2 G P=S/G=e^{-2G} P=S/G=e−2G
帧时越长,G越大,成功率越低
二进制树形搜索算法、混合算法(EB-FSA
,FSAPB
等)
明文m,加密算法E,加密密钥K,密文c,解密算法D,解密密钥 K − 1 K^-1 K−1
即单钥体制,加密密钥和解密密钥相同。
点此了解移位密码
点此了解仿射密码
点此了解希尔密码
点此了解S-DES加密算法
即公钥体制、双钥体制,加密密钥和解密密钥不同,并且不能从加密密钥得到解密密钥。
产生主要是因为密钥分配问题和对数字签名的需求。
E和D需要满足:
- D(E(m))=m
- E推导D非常困难
- 使用明文攻击不能破译
点此了解RSA加密
点此了解ECC加密
点此查看三次认证详细内容
三次认证的过程
- 阅读器发送查询口令的命令给应答器,应答器作为应答响应传送所产生的一个随机数RB给阅读器。
- 阅读器产生一个随机数RA使用共享的密钥K和共同的加密算法 E k E_k Ek ,算出加密数据块TOKENAB,并将TOKENAB传送给应答器。
TOKENAB = E k E_k Ek(RA,RB)- 应答器接受到TOKENAB后,进行解密,将取得的随机数与原先发送的随机数RB进行比较,若一致,则阅读器获得了应答器的确认。
- 应答器发送另一个加密数据块TOKENBA给阅读器,TOKENBA= E k E_k Ek(RB1,RA)
- 阅读器接收到TOKENBA并对其解密,若收到的随机数与原先发送的随机数RA相同,则完成了阅读器对应答器的认证。
点此了解二维码详细内容
点此查看M1卡访问控制详情
- 第一扇区(0 扇区)的第一数据块(0 块)。
- 其中包含 IC 制造商数据。该块在生产测试中编程并实施写保护
- 用于存放厂商代码,已经固化,不可更改。
- 所有扇区的0,1,2三个块,用于存储数据。
- 但它们的访问权限是由块3中的访问控制位控制的。
即:一个扇区中的最后一个块–块 3
组成:
- 密钥 A(强制)和密钥 B(可选)
- 该扇区块的访问条件(字节 6 至字节 9 ),对应16进制控制字4个值
每个扇区的尾块(块3)包含访问控制信息,这些信息由称为访问控制位(C1, C2, C3)的三位组成
它们的组合定义了对数据块的读、写、增加、减少
等操作的访问权限
以下是这些访问控制位的表示方法
块类型 | 访问控制位 |
---|---|
数据块0(块0) | C10, C20, C30 |
数据块1(块1) | C11, C21, C31 |
数据块2(块2) | C12, C22, C32 |
尾块(块3) | C13, C23, C33 |
对于每个数据块,都有一组访问控制位。块3负责块数据块的权限控制,同时,块3中还包含了一组访问控制位,用于控制尾块本身的访问权限
字节位 | ||||||||
---|---|---|---|---|---|---|---|---|
字节6 | ||||||||
字节7 | C13 | C12 | C11 | C10 | ||||
字节8 | C33 | C32 | C31 | C30 | C23 | C22 | C21 | C20 |
字节9 |
- 字节9是备用字节,一般不用
Cxx代表需要取反
案例1
块3的控制字是FF 07 80 69
字节位 | ||||||||
---|---|---|---|---|---|---|---|---|
FF – 字节6 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
C13 | C12 | C11 | C10 | |||||
07 – 字节7 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
C33 | C32 | C31 | C30 | C23 | C22 | C21 | C20 | |
80 – 字节8 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
块 | 三位访问控制位 | 权限(注意两个权限表) |
---|---|---|
0 | C10,C20,C30 — 000 | 通过A或者B密码认证后可读,可写,可进行加值和减值操作 |
1 | C11,C21,C31 — 000 | 通过A或者B密码认证后可读,可写,可进行加值和减值操作 |
2 | C12,C22,C32 — 000 | 通过A或者B密码认证后可读,可写,可进行加值和减值操作 |
3 | C13,C23,C33 — 001 | A密码不可读,验证A或者B密码后可改写A密码。验证A或者B密码后,可读可改写存取控制 。 验证A密码或者B密码后,可读可改写B密码 |
案例2
块3的控制字是E8 73 C1 69
字节位 | ||||||||
---|---|---|---|---|---|---|---|---|
E8– 字节6 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 |
C13 | C12 | C11 | C10 | |||||
73 – 字节7 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 |
C33 | C32 | C31 | C30 | C23 | C22 | C21 | C20 | |
C1– 字节8 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
块 | 三位访问控制位 | 权限(注意两个权限表) |
---|---|---|
0 | C10,C20,C30 — 110 | 通过A或者B密码认证后可读、减值,通过B密码认证后可写、加值 |
1 | C11,C21,C31 — 100 | 通过A或者B密码认证后可读,通过B密码认证后可写,不可进行加值和减值操作 |
2 | C12,C22,C32 — 101 | 通过B密码认证后可读,不可进行写、加值和减值操作 |
3 | C13,C23,C33 — 001 | A密码不可读,验证A或者B密码后可改写A密码。验证A或者B密码后,可读可改写存取控制 。 验证A密码或者B密码后,可读可改写B密码 |
点此了解ONS详细信息
通过长度确定EPC编码类型,注意版本号长度有2和8两种。
阅读器
将读到的EPC编码上传到本地服务器
。有本地服务器安装的Savant
软件对信息集中处理。本地服务器通过本地ONS服务器或路由器到达远程
ONS
服务器,查找所需EPC编码对应的EPCIS服务器地址,然后本地服务器就可以与对应的EPCIS
服务器通信。
这里联系前面的M1卡存取控制理解
arduino UNO + RC522,详细内容点此查看
#include // 包含 SPI 总线库
#include // 包含 RFID 读卡器库
#define SS_PIN 10 // 从选择引脚
#define RST_PIN 5 // 复位引脚
MFRC522 mfrc522(SS_PIN, RST_PIN); // 实例化 MFRC522 读卡器对象
MFRC522::MIFARE_Key key; // 创建一个名为 'key' 的 MIFARE_Key 结构体,用于保存卡片信息
int block = 2; // 要写入和读取的块号(这里只能选数据块【0,1,2】)
byte blockcontent[16] = {"Last-Minute-Engg"}; // 定义一个包含 16 字节的数组,用于写入卡片的一个块
//byte blockcontent[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // 全部为零。可以用来删除一个块。
byte readbackblock[18]; // 用于读取一个块的数组
void setup()
{
Serial.begin(9600); // 初始化与电脑的串行通信
SPI.begin(); // 初始化 SPI 总线
mfrc522.PCD_Init(); // 初始化 MFRC522 读卡器(PCD 代表 proximity coupling device,即近场耦合设备)
Serial.println("Scan a MIFARE Classic card");
// 为读取和写入功能准备安全密钥。
for (byte i = 0; i < 6; i++)
{
key.keyByte[i] = 0xFF; // keyByte 在库的 .h 文件中的 "MIFARE_Key" 结构体定义中已经定义
}
}
void loop()
{
// 寻找新的卡片
if (!mfrc522.PICC_IsNewCardPresent())
{
return;
}
// 选择一张卡片
if (!mfrc522.PICC_ReadCardSerial())
{
return;
}
Serial.println("card selected");
// 将 blockcontent 数组写入卡片块
writeBlock(block, blockcontent);
// 读取块数据
readBlock(block, readbackblock);
// 如果要查看写入整个 1k 存储器的内容,请取消下面一行的注释。
//mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
// 打印块内容
Serial.print("read block: ");
for (int j = 0; j < 16; j++)
{
Serial.write(readbackblock[j]);
}
Serial.println("");
}
// 写入指定块,参数为块的编号和写入块的内容
int writeBlock(int blockNumber, byte arrayAddress[])
{
// 这确保我们只写入数据块。每 4 个块中有一个用于访问/安全信息的尾块。
int largestModulo4Number = blockNumber / 4 * 4;
int trailerBlock = largestModulo4Number + 3; // 确定扇区的尾块
if (blockNumber > 2 && (blockNumber + 1) % 4 == 0)
{
Serial.print(blockNumber);
Serial.println(" is a trailer block:");
return 2;
}
Serial.print(blockNumber);
Serial.println(" is a data block:");
// 对所需块进行身份验证以访问
byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK)
{
Serial.print("PCD_Authenticate() failed: ");
Serial.println(mfrc522.GetStatusCodeName(status));
return 3; // 返回 "3" 作为错误消息
}
// 写入块数据
status = mfrc522.MIFARE_Write(blockNumber, arrayAddress, 16);
//status = mfrc522.MIFARE_Write(9, value1Block, 16);
if (status != MFRC522::STATUS_OK)
{
Serial.print("MIFARE_Write() failed: ");
Serial.println(mfrc522.GetStatusCodeName(status));
return 4; // 返回 "4" 作为错误消息
}
Serial.println("block was written");
}
// 读取指定块,参数是一个是块号,另一个是读取的存内容
int readBlock(int blockNumber, byte arrayAddress[])
{
int largestModulo4Number = blockNumber / 4 * 4;
int trailerBlock = largestModulo4Number + 3; // 确定扇区的尾块(块3)
// 对所需块进行身份验证以访问
byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK)
{
Serial.print("PCD_Authenticate() failed (read): ");
Serial.println(mfrc522.GetStatusCodeName(status));
return 3; // 返回 "3" 作为错误消息
}
// 读取块数据
byte buffersize = 18; // 我们需要定义一个带有读取缓冲区大小的变量,因为下面的 MIFARE_Read 方法需要一个指向包含大小的变量的指针...
status = mfrc522.MIFARE_Read(blockNumber, arrayAddress, &buffersize); // &buffersize 是指向 buffersize 变量的指针;MIFARE_Read 需要一个指针而不仅仅是一个数字
if (status != MFRC522::STATUS_OK)
{
Serial.print("MIFARE_read() failed: ");
Serial.println(mfrc522.GetStatusCodeName(status));
return 4; // 返回 "4" 作为错误消息
}
Serial.println("block was read");
}
Scan a MIFARE Classic card //表示正在寻找卡片
card selected //表示找到了卡片
block was written //执行了写入块的操作
block was read //执行了读取块的操作
read block: Last-Minute-Engg //成功读取了块,并显示了块的内容
+------------------+
| 开始 |
+------------------+
|
V
+------------------+
| 初始化设置 |
+------------------+
|
V
+------------------+
| 主循环 |
+------------------+
|
V
+------------------+
| 检查新卡片 |
+------------------+
|
V
+--------------+
| 有新卡片? |<-------+
+--------------+ |
| |
V |
+--------------+ |
| 选择卡片 | |
+--------------+ |
| |
V |
+--------------+ |
| 卡片选择成功? |--------+
+--------------+
| 否
V
+------------------+
| 返回主循环 |
+------------------+
|
V
+--------------+
| 写入块 |
+--------------+
|
V
+--------------+
| 写入成功? |---------+
+--------------+ |
| 否 |
V |
+-------------------+ |
| 返回主循环 | |
+-------------------+ |
| |
V |
+--------------+ |
| 读取块 | |
+--------------+ |
| |
V |
+--------------+ |
| 读取成功? |---------+
+--------------+
| 否
V
+-------------------+
| 返回主循环 |
+-------------------+
|
V
+--------------+
| 打印块内容 |
+--------------+
|
V
+------------------+
| 继续主循环? |
+------------------+
|
V
+------------------+
| 结束 |
+------------------+