有趣的Hack-A-Sat黑掉卫星挑战赛——被破坏的阿波罗计算机(解法二)

news2024/11/23 22:19:13

国家太空安全是国家安全在空间领域的表现。随着太空技术在政治、经济、军事、文化等各个领域的应用不断增加,太空已经成为国家赖以生存与发展的命脉之一,凝聚着巨大的国家利益,太空安全的重要性日益凸显[1]。而在信息化时代,太空安全与信息安全紧密地结合在一起。

2020年9月4日,美国白宫发布了首份针对太空网络空间安全的指令——《航天政策第5号令》,其为美国首个关于卫星和相关系统网络安全的综合性政策,标志着美国对太空网络安全的重视程度达到新的高度。在此背景下,美国自2020年起,连续两年举办太空信息安全大赛“黑掉卫星(Hack-A-Sat)”,在Hack-A-Sat太空信息安全挑战赛深度解析》一书中有详细介绍,本文介绍了Hack-A-Sat黑掉卫星挑战赛的寻找阿波罗导航计算机中被修改的PI(apollo_gcm)这道赛题的解题过程。这里是解法二。

题目介绍

Step right up, here's one pulled straight from the history books. See if you can DSKY your way through this challenge! (Thank goodness VirtualAGC is a thing…)

从上述题目介绍可知,这道题目需要比较旧的知识,与阿波罗导航计算机(Apollo Guidance Computer,AGC)相关,并且要用到DSKY。DSKY是AGC的输入/输出,类似于现代计算机的显示器、键盘。

主办方给出了一个链接地址,使用netcat打开该链接后,会获得一段提示信息,如下:

The rope memory in the Apollo Guidance Computer experienced an unintended 'tangle' just prior to launch. While Buzz Aldrin was messing around with the docking radar and making Neil nervous; he noticed the value of PI was slightly off but wasn’t exactly sure by how much. It seems that it was changed to something slightly off 3.14 although still 3 point something.

The Commanche055 software on the AGC stored the value of PI under the name "PI/16", and

although it has always been stored in a list of constants, the exact number of constants in that memory region has changed with time.

Help Buzz tell ground control the floating point value PI by connecting your DSKY to the AGC Commanche055 instance that is listening at 172.17.0.1:19008

What is the floating point value of PI?:

通过分析,主要给出如下信息:

  • 阿波罗飞船就要发射,但是飞船上的AGC出现了一点状况,其中圆周率PI的值发生了变化,不再是14,而是有一点点变化,但是还是3点几。
  • PI值是通过AGC上的Commanche055软件存储的,存储的名称是“PI/16”。
  • PI与其他常数存储在一起,因为常数的数量会有变化,所以存储位置不固定。
  • AGC上的存储器是线存储器(Rope Memory)。
  • 使用DSKY通过地址17.0.1:19008可以连接到AGC的Commanche055软件。

要求参赛者找到当前PI的值。

编译及测试

这个挑战题的代码位于apollo目录下,查看challenge、solver目录下的Dockerfile,发现其中用到的是python:3.7-slim,为了加快题目的编译进度,在apollo目录下新建一个文件sources.list,内容如下:

deb https://mirrors.aliyun.com/debian/ bullseye main non-free contrib

deb-src https://mirrors.aliyun.com/debian/ bullseye main non-free contrib

deb https://mirrors.aliyun.com/debian-security/ bullseye-security main

deb-src https://mirrors.aliyun.com/debian-security/ bullseye-security main

deb https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib

deb-src https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib

deb https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib

deb-src https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib

将sources.list复制到apollo、challenge、solver目录下,修改challenge、solver目录下的Dockerfile,在所有的FROM python:3.7-slim下方添加:

ADD sources.list /etc/apt/sources.list

打开终端,进入apollo所在目录,执行命令:

sudo make build

此时如果使用make test命令进行测试,等待30~60秒,会出现如图7-10所示的结果。可以发现测试中,找到的PI值由两个八进制数组成(AGC采用八进制表示各种数据),具体解释后面会有介绍,找到PI值后,题目给出了flag值。

图7-10  apollo挑战题的测试结果

相关背景知识

1.阿波罗导航计算机AGC

阿波罗计划是美国在1961年—1972年组织实施的一系列载人登月飞行任务,其目的是实现载人登月飞行和人对月球的实地考察,为载人行星飞行和探测进行技术准备。它是世界航天史上具有划时代意义的一项成就。阿波罗计划始于1961年5月,至1972年12月第6次登月成功结束,历时约11年,耗资255亿美元。阿波罗号飞船由指挥舱、服务舱和登月舱3部分组成。

(1)指挥舱:是宇航员在飞行中生活和工作的座舱,也是全飞船的控制中心。指挥舱为圆锥形,高3.2m,重约6吨。指挥舱分前舱、宇航员舱和后舱3部分。前舱内放置着陆部件、回收设备和姿态控制发动机等。宇航员舱为密封舱,存有供宇航员生活14天的必需品和救生设备。后舱内装有10台姿态控制发动机,各种仪器和贮箱,姿态控制、制导导航系统,以及船载计算机和无线电分系统等。

(2)服务舱:其前端与指挥舱对接,后端有推进系统主发动机喷管。舱体为圆筒形,高6.7m,直径4m,重约25吨。主发动机用于轨道转移和变轨机动。姿态控制系统由16台火箭发动机组成,用于飞船与第三级火箭分离、登月舱与指挥舱对接和指挥舱与服务舱分离等。

(3)登月舱:由下降级和上升级组成,地面起飞时重14.7吨,宽4.3m,最大高度约7m。其中下降级由着陆发动机、4根着陆架和4个仪器舱组成,上升级是登月舱主体。宇航员完成月面活动后驾驶上升级返回环月轨道与指挥舱会合。上升级由宇航员座舱、返回发动机、推进剂贮箱、仪器舱和控制系统组成。宇航员座舱可容纳2名宇航员,舱内设有导航、控制、通信、生命保障和电源等设备。

AGC是阿波罗计划中的主要船载计算机,使用在所有的登月任务中。指挥舱和登月舱都有AGC,但是两者运行的软件不同。AGC及其软件是在麻省理工学院仪器实验室(现在称为德雷珀实验室)开发的。性能参数如下:

  • RAM为2048字,一个字是15bit。
  • ROM为36864字,一个字是15bit。
  • 每秒最多可执行85 000条指令。
  • 使用28V直流供电,电流为5A。
  • 具备输入输出DSKY。

题目中使用的是VirtualAGC。VirtualAGC是AGC爱好者制作的一个AGC模拟器,是开源软件,可以运行AGC上的程序。此外,AGC普遍使用的是八进制,本书采用Python的写法,数字前加“0o”表示八进制数,还有一种表示方法,就是数字加一个下标“8”。

2.线存储器

线存储器是一种只读存储器(ROM)。利用磁环改变导线上电压的状态,如果导线穿过磁环,导线上的电压就会发生改变。系统检测到这种改变后,就会把这条导线上的数据解释为1,如果导线没有穿过磁环,那么导线上的电压不发生改变,系统就会把这条导线上的数据解释为0。线存储器如图7-11所示。

(a)

(b)

(c)

图7-11  线存储器

AGC上的ROM是以Bank组织的,每个bank为1024字,每个字为15bit,每个Bank中的字的地址是从0o2000(对应十进制1024)开始的,所以给出一个数据的Bank号及Bank中的地址address,可以计算实际地址,方法为:

Bank×20008 + address - 20008

例如,第0o27个Bank中的地址0o3355,对应的实际地址为:

278×20008 + 33558 - 20008 = 573558

3.DSKY

DSKY类似于现代的显示器和键盘,但是那时候的显示器和键盘比较简单,如图7-12、图7-13所示。可以发现,上半部分是两个显示屏,下半部分是一个键盘,可以用于输入。

图7-12  DSKY

图7-13  飞船舱内操作面板,其中中间偏左有DSKY

为了更加清晰地了解DSKY,这里以VirtualAGC中实现的yaDSKY(yet another DSKY)为例进行介绍,其界面如图7-14所示。yaDSKY就是DSKY的模拟器,其界面和功能是完全一致的。

先介绍上半部分的显示屏,需要关注的是右半边,都是使用7段数码管来实现的,第二行有一个VERB,下方对应两个7段数码管,第二行还有一个NOUN,下方也对应两个7段数码管,接下来是三行连续的显示,每一行都是5个7段数码管,而且每一行最前方有一个类似加号的显示,显示的是正、负。

再介绍下半部分的键盘,需要关注的是,最左边一个按键名称是VERB,另一个是NOUN,与上半部分的显示刚好对应。在最右边有一个按键名称是ENTR,应该就是类似于现代键盘的回车键。

图7-14  yaDSKY的界面

这里就涉及DSKY的操作方法了,DSKY采用动词VERB(简称V)+名词NOUN(简称N)的方式进行控制操作,其中V、N的部分取值及其作用如图7-15所示。

(a)V的取值

(b)N的取值

图7-15  DSKY的V、N的部分取值(续)

注意到其中V的取值最下面的0o27,可以用来显示存储器中的数据,所以使用DSKY查询存储器特定地址的方式为:依次输入V27N02E,然后会发现DSKY上27、02两个数字会闪,此时输入57355,按ENTR键,即可得到地址为57355的数字,并在下面3行的第1行显示。此时再次按ENTR键,又可以输入一个地址,再按ENTR键,就会显示存储器中这个新地址存储的数据,如图7-16所示。

图7-16  使用DSKY读取ROM指定地址存储的数据

4.AGC中浮点数表示

AGC中字有15位,还带1个奇偶校验位,但是这个奇偶校验位只供硬件使用,软件访问不了。一个字采用MSB的方式,最高位是第15位,最低位是第1位,如图7-17所示,最后一个P是奇偶校验位。

图7-17  AGC中字的格式

1)单精度浮点数(Single-Precision,SP)的格式

SP使用一个15位的字表示,第15位是符号位,为1表示负数,为0表示正数。第14~第1位构成SP的小数部分。如果是正数,那么SP的值就是:

如果是负数,那么SP的值就是:

比如:

  • +0 在AGC中使用SP表示,就是000000000000000;
  • -0 在AGC中使用SP表示,就是111111111111111;
  • 1/2 在AGC中使用SP表示,就是01000000000000;
  • -1/2 在AGC中使用SP表示,就是101111111111111;
  • 1/4 在AGC中使用SP表示,就是001000000000000;
  • 3/4 在AGC中使用SP表示,就是011000000000000。

2)双精度浮点数(Double-Precision,DP)的格式

为了提高精度,使用两个连续的15位的字表示一个DP。前一个字称为字1,后一个字称为字0,字1的第14位~第1位表示较高的有效位,字0的第14位~1位表示较低的有效位,并且字1的第15位是符号位,如图7-18所示。

图7-18  DP格式

一般而言,这两个字的第15位是一致的,但是也有不一致的情况,这里只考虑一致的情况。如果是正数,那么DP的值就是:

如果是负数,那么DP的值就是:

现在,回头检查一下前文在进行测试时,显示的PI/16的结果,如图7-10所示,为0o6413 0o11416,这是一个DP,按照DP的定义,其对应的十进制数为:

这个就是PI/16的值,将其乘以16,得到PI的值为3.26103293895721435546875,可见确实是偏了一点。

解法二

解法二与解法一的思路是一致的,都是寻找到ROM中存储数据0o37777的位置,然后将其前两个位置的数据读出,即PI/16的值。但是,解法二不使用yaDSKY,而是通过分析DSKY的原理,编写程序模拟DSKY与AGC的交互过程,读取AGC中ROM的数据。

1.AGC I/O基本格式

AGC的I/O(Input/Output,输入/输出)使用4字节的数据包,格式如图7-26所示,最左边是MSB,最右边是LSB。其中ppppppp代表不同的通道,一共有128个通道,与本挑战题相关的通道如表7-1所示。ddddddddddddddd表示15位数据。

图7-26  AGC I/O数据包的格式

表7-1  与本挑战题相关的通道

通  道  号

作    用

输出通道0o10(八进制)

用于驱动7段数码管的显示

输入通道0o15(八进制)

用于得到DSKY的按键信息

2.键盘定义

DSKY有19个按键,每个按键使用5位编码,如表7-2所示。按键的编码信息会存储在AGC I/O的最低5位中。

表7-2  DSKY的按键编码

按    键

二进制编码

十进制编码

八进制编码

0

10000

16

20

1

00001

1

1

续表

按    键

二进制编码

十进制编码

八进制编码

2

00010

2

2

3

00011

3

3

4

00100

4

4

5

00101

5

5

6

00110

6

6

7

00111

7

7

8

01000

8

10

9

01001

9

11

VERB

10001

17

21

RSET

10010

18

22

KEY REL

11001

25

31

+

11010

26

32

-

11011

27

33

ENTR

11100

28

34

CLR

11110

30

36

NOUN

11111

31

37

PRO

当通道号是0o32(八进制)时,第14位为1,表示PRO按键按下,本挑战题的解析过程使用不到PRO按键,读者无须关注

3.7段数码管显示定义

为了理解AGC是如何驱动7段数码管显示的,需要首先了解DSKY上7段数码管的编号约定,如图7-27所示。DSKY I/O中通道号如果是0o10,那么表示驱动7段数码管的显示,此时15位数据的定义如图7-28所示。可以发现分为了4部分:

  • 第15位~12位为RLYWD(Relay Word):选择要驱动显示的7段数码管,一次可以最多选中两个7段数码管。
  • 第11位为DSPC:控制VERB、NOUN的闪烁,控制显示屏下面3行数据最左侧的符号位。
  • 第10位~6位为DSPH:给出RLYWD选中的两个7段数码管的左边数码管的显示数字。
  • 第5位~1位为DSPL:给出RLYWD选中的两个7段数码管的右边那个数码管的显示数字。

其中RLYWD取不同的值时的作用如表7-3所示。例如,当RLYWD为1011时,会驱动显示M1、M2两个7段数码管,其中M1显示的数字存储在DSPH,M2显示的数字存储在DSPL;当RLYWD为0001时,会驱动显示编号为34、35的两个7段数码管,其中编号为34的数码管显示的数字存储在DSPH,编号为35的数码管显示的数字存储在DSPL,另外,此时DSPC位控制编号为3-的符号位的显示。7段数码管的显示与DSPH、DSPL的值的对应关系如表7-4所示。

图7-27  DSKY上7段数码管的编号

图7-28  当DSKY I/O中通道号为驱动7段数码管显示时的15位数据的定义

表7-3  当DSKY I/O为驱动7段数码管显示时,15位数据位的含义

第15位~12位

RLYWD

第11位

DSPC

第10位~6位

DSPH

第5位~1位

DSPL

1011

M1

M2

1010

FLASH

V1

V2

1001

N1

N2

1000

UPACT

11

0111

1+

12

13

0110

1-

14

15

0101

2+

21

22

0100

2-

23

24

0011

25

31

0010

3+

32

33

0001

3-

34

35

表7-4  7段数码管的显示DSPH、DSPL的值与的对应关系

DSPH或者DSPL的值

7段数码管显示

00000(对应十进制数0)

10101(对应十进制数21)

0

00011(对应十进制数3)

1

11001(对应十进制数25)

2

11011(对应十进制数27)

3

01111(对应十进制数15)

4

11110(对应十进制数30)

5

11100(对应十进制数28)

6

10011(对应十进制数19)

7

11101(对应十进制数29)

8

11111(对应十进制数31)

9

4.代码实现

有了上述基础知识,就可以编写代码实现了,主要代码如下:

# 按照表7-4,定义数字与7段数码管显示的对应,用一个数组实现

numLookup = {

0 : " ",

3 : "1",

15: "4",

19: "7",

21: "0",

25: "2",

27: "3",

28: "6",

29: "8",

30: "5",

31: "9"

}

# 按照表7-2,定义按键与编码的对应,也用一个数组实现

keys = {

'0': 16,

'1': 1,

'2': 2,

'3': 3,

'4': 4,

'5': 5,

'6': 6,

'7': 7,

'8': 8,

'9': 9,

'e': 28,

'v': 17,

'n': 31,

'c': 30,

}

# 按照图7-28的格式,定义两个函数,分别用于组装形成AGC I/O数据包、分析AGC I/O数据包

# 第一个函数:组装形成AGC I/O数据包,输入的参数是通道号、数据

def FormIoPacket(chan, val):

if (chan < 0 or chan > 0x1ff):

return None

if (val < 0 or val > 0x7fff):

return None

return struct.pack("BBBB",

0xFF & ( chan >> 3),

0xFF & ( 0x40 | ((chan << 3) & 0x38) | ((val >> 12) & 0x7) ),

0xFF & ( 0x80 | ((val >> 6) & 0x3F)),

0xFF & ( 0xc0 | (val & 0x3F) )

)

# 第二个函数:分析AGC I/O数据包,输出通道号、数据

def ParseIoPacket(bs):

channel = ((bs[0] & 0x1F) << 3) | ((bs[1] >> 3) & 7)

value = ((bs[1] << 12) & 0x7000) | ((bs[2] << 6) & 0xFC0) | (bs[3] & 0x3F)

ubit = (0x20 & bs[0])

return channel,value,ubit

# 按照表7-2的格式,定义SendKey函数,用于发送键盘按键信息,注意,其中的通道号是0o15

def SendKey(keyCode):

return FormIoPacket(0o15, keyCode)

# 定义显示面板对应的7段数码管,分别是:

# 2个VERB、2个NOUN

# 第1行5个数码管

# 第2行5个数码管

# 第3行5个数码管

Verb = [0] * 2

Noun = [0] * 2

R1   = [0] * 5

R2   = [0] * 5

R3   = [0] * 5

# 定义一个显示函数,通过传递来的编码,查找numLookup数组,得到要显示的对应数字

def formatNums(nums):

out = ""

for num in nums:

out += numLookup[num]

return out

# 下面两个函数参考表7-3,依据RLYWD的值,确定那个数码管显示数字,将相应的数字赋值过去

def doLeft(digit, vL):

if vL == 0:

pass

elif digit == 0x3800:

R1[1] = vL

elif digit == 0x3000:

R1[3] = vL

elif digit == 0x1000:

R3[1] = vL

elif digit == 0x800:

R3[3] = vL

def doRight(digit, vR):

if vR == 0:

pass

elif digit == 0x4000:

R1[0] = vR

elif digit == 0x3800:

R1[2] = vR

elif digit == 0x3000:

R1[4] = vR

elif digit == 0x1800:

R3[0] = vR

elif digit == 0x1000:

R3[2] = vR

elif digit == 0x800:

R3[4] = vR

# 定义一个处理AGC I/O数据包的函数,注意其中只处理通道号为0o10的数据包,参考表7-1可知,这个
# 通道是驱动7段数码管显示的通道

def HandlePacket(bs):

while len(bs) > 4:

chan, val, ubit = ParseIoPacket(bs[:4])

bs = bs[4:]

if (chan != 0o10):

continue

digit = 0x7800 & val        # 取出RLYWD的值

vL = (val >> 5) & 0x1F   # 取出DSPH的值

vR = val & 0x1F              # 取出DSPL的值

doLeft(digit, vL)        # 调用前面定义的两个函数,确定要显示的数字

doRight(digit, vR)

return bs

......

if __name__ == "__main__":

Host = os.getenv("HOST", "localhost")

Port = int(os.getenv("PORT", 31450))

Ticket = os.getenv("TICKET", "")

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.connect((Host, Port))

if len(Ticket):

sock.recv(128)

sock.send((Ticket + "\n").encode("utf-8"))

for line in sock.recv(2048).split(b'\n'):

if b"listening" in line:

Host2,Port2 = line.decode('utf-8').split(" ")[-1].split(":")

print(line.decode('utf-8'))

time.sleep(5)

Port2 = int(Port2)

print("Connecting to:",Host2,Port2)

sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock2.connect((Host2, Port2))

lock = threading.Lock()

reader = threading.Thread(target=readLoop, args=(sock2,lock))

reader.start()

# 发送读取ROM的指令

for b in "v27n02":

sock2.send(SendKey(keys[b]))

time.sleep(0.1)

time.sleep(1)

# 开始搜索

startCount = 45

nums = []

for ii in range(0,20):

sock2.send(SendKey(keys['e']))

time.sleep(0.9)

# 读取的地址是从0o57355开始的20个位置

command = "573" + oct(startCount + ii)[2:]

for idx,b in enumerate(command):

sock2.send(SendKey(keys[b]))

while True:

time.sleep(0.5)

lock.acquire()

get = R3[idx]

lock.release()

if numLookup[get] == b:

break

sock2.send(SendKey(keys['e']))

time.sleep(0.9)

while True:

try:

lock.acquire()

num = (int(formatNums(R1),8))

lock.release()

except:

continue

break

# 若读取到了0o37777,则停止往下读取

if num == 0o37777:

break

else:

nums.append(num)

running = False

hi,lo = nums[-2:]             # 取出数据0o37777对应存储地址的前两个地址存储的数字

print(oct(hi), oct(lo))

reader.join()

hi_b = bin(hi)[2:]

hi_b = '0' * ( 14-len(hi_b) ) + hi_b

lo_b = bin(lo)[2:]

lo_b = '0' * ( 14-len(lo_b) ) + lo_b

bits = hi_b + lo_b

# 将数据0o37777对应存储地址的前两个地址存储的数字,按照AGC中DP的解读,计算其对应的浮点数

value = 0.0

for idx, bit in enumerate(bits):

if bit == '1':

value += 2.0**(-1 - idx)

# 上面计算得到的DP乘以16,就是PI的值

sock.send(bytes("{:1.09f}\n".format(value * 16), 'utf-8'))

for line in sock.recv(1024).split(b'\n'):

print(line.decode('utf-8'))

sys.stdout.flush()

sock.close()

sock2.close()

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

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

相关文章

全网最火爆,Web自动化测试POM模式分层实战,框架封装看这一篇就够了

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 线性脚本以快递 100…

【可信平台】SO202303191426,销售订单未同步,销售出库单未同步

1.销售订单未同步 这里先说下推送逻辑:1.物料描述带有‘再生’ 。2.公司是芮邦 这个物料应该在EOS里查,可我不会,我在MES里查,的确符合条件。 可信平台同步逻辑,是销售订单同步了,才会同步销售出库单。 这个SO销售订单就没同步,要先解决这个问题。 可以在接口看日志…

HighTec编译器错误记录

目录 1、HighTec安装后缺少Universal Debug Engine 2、HighTec工程改名后不能跳转函数定义&#xff0c;提示找不到定义。 3、HighTec工程重复编译 1、HighTec安装后缺少Universal Debug Engine 在HighTec安装后&#xff0c;没有调试UDE&#xff0c;重装系统后还是没有&#x…

STM32F4_OLED显示

目录 1. OLED简介 2. 硬件模块 3. 8080并行接口 4. SPI方式 5. SSD1306常用命令表 6. 完整源码 (STM32F407对应的源码) 6.1 oled.c 6.2 oled.h 6.3 oledfont.h 7. IIC接口下的OLED(STM32F407搭配4Pin OLED) 7.1 OLED.c 7.2 OLED.h 7.3 OLED_Font.h 7.4 MyI2C.c …

QTableview 隐藏单元格内控件无效的原因

QTableview 隐藏单元格内控件无效的原因 背景&#xff1a; 在QTableview的单元格中创建多个QComboBox&#xff0c;当某条件成立时&#xff0c;隐藏特定单元格中的QComboBox&#xff0c;使得该单元格为空。 DEMO&#xff1a; #ifndef MAINWINDOW_H #define MAINWINDOW_H#inc…

【Redis】Redis键(key)

常用命令 常用案例 keys * 查看当前库所有的key 127.0.0.1:6379> keys * 1) "k1"exists key 判断某个key是否存在&#xff0c;存在几个则返回几&#xff0c;不存在则返回0 127.0.0.1:6379> exists k1 (integer) 1 127.0.0.1:6379> exists k2 (integer)…

西工大电子实习单片机-7+1亮灯编程C语言代码分享

电子实习是西工大大多数学生绕不开的一门实习课程。单片机是电子实习课程中较为重要的一部分&#xff0c;需要上两次。我们在单片机编程时在西工大电脑机房老系统上往往由于大一学习的C语言忘得一干二净而无从下手。流水灯成了流水账。 废话不多说&#xff0c;仅供参考。71是指…

分享5款办公效率工具|让你早点下班

如果每天你的工作都很多&#xff0c;做不完需要加班怎么办? 不知道你会不会加班&#xff0c;但是我肯定不会&#xff0c;因为我知道哪些高效率的办公工具&#xff0c;可以帮助我早点下班&#xff0c;今天来给大家分享一下。 1.FlowUs FlowUs 是一款为个人和团队打造的新一代生…

Netty通信技术进阶二

Netty核心组件 1. Bootstrap2 Channel3. EventLoopGroup 和 EventLoop3.1 eventLoopThreads 是多少&#xff1f; 4. ChannelHandler & ChannelHandlerContext & ChannelPipeline4.1 复用Handler4.2 ChannelInboundHandlerAdapter or SimpleChannelInboundHandler 5. By…

Linux系统之部署ZFile在线网盘服务

Linux系统之部署ZFile在线网盘服务 一、ZFile介绍1.ZFile简介2.ZFile特点 二、本地环境介绍1.本次实践说明2.本地环境规划 三、安装环境依赖1.安装java2.检查java版本 四、下载ZFile软件1.创建安装部署目录2.声明安装路径3.下载ZFile软件包4.解压ZFile软件包5.授权启动停止脚本…

FOC专题--环路PID算法拆分分析

foc中&#xff0c;其实foc算法并不是最难理解的&#xff0c;反而是在其中使用的PID算法&#xff0c;之前我只会套用别人的代码&#xff0c;但并不理解其中的各参数含义&#xff0c;导致在实际调整PI参数的时候&#xff0c;很难调到合适的值。 在实际理解什么是PID算法以及各参数…

【C++引用 】

目录 前言一、引用的概念二、使用引用时注意事项三、引用的使用场景及优势四、常引用、引用的权限五、引用和指针的区别 前言 相信大家应该在网上看过这样的段子。 大家都知道鲁迅原名周树人&#xff0c;浙江绍兴人。"鲁迅"是"周树人"的别名或者说是笔名…

TCP版本的 echo server 和 echo client

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言Tcp的api展示服务端客户端存在的问题解决问题服务端和客户端的大致流程 前言 上一篇文章我们介绍了UCP的客户端与服务器的一个简单实例,这篇我们简单的来介绍T…

111.【金橘社区1.0】

金橘社区1.0版本 (一)、SpringBoot整合SpringSecurity1.导入依赖2.数据库3.登入表单4. 添加配置类 SecurityConfig5.接口实现类 CkqnUserServiceImpl6.前端认证问题 (二)、SpringBoot整合Ajax1.登入表单2. JavaScript (三)、SpringBoot整合editor.md1.编写页面(1).前端页面(2).…

Windows安装RedisJSON(无需编译)

文章目录 Windows安装RedisJSON下载解压配置文件启动服务启动客户端 Windows安装RedisJSON 下载 打开网址 https://github.com/zkteco-home/RedisJson。 在网页的右上角&#xff0c;点击“Code”按钮&#xff0c;然后选择“Download ZIP”以下载最新版本的RedisJSON。 网盘 …

C6678-控制GPIO输入/输出

C6678-控制GPIO输入/输出 术语寄存器起始地址原理输入输出测试中断功能原理中断原理框图芯片中断控制器原理框图内核中断控制器原理框图中断路由架构一级中断表二级中断表CIC0二级中断CIC1二级中断CIC2二级中断CIC3 中断演示代码参考资料 术语 NMI&#xff1a; 不可屏蔽中断CI…

6、在vscode上利用cmake创建第一个简单C++程序

文章目录 &#xff08;1&#xff09;前期准备工作&#xff1a;即安装对应的环境1&#xff09;在vscode上安装插件&#xff1a;C/C、Cmake、CMake tools2&#xff09;安装Cmake环境&#xff08;这是在前面博客提到的已经安装好gcc等环境的前提下进行的&#xff09; &#xff08;…

Springboot基础学习之(二十二):异步任务和邮件任务

方向一&#xff1a;高效学习方法分享 我认为学习的最好的办法就是做笔记:本人特别喜欢在网上学习一些课堂外的知识&#xff0c;但是如果你没有及时的复习&#xff0c;要想找到自己想要的知识该怎么办呢&#xff1f;对&#xff0c;就是做笔记我在csdn这个app发的所有内容都是笔记…

Android UI布局优化之include、merge与ViewStub标签的巧用方法

前言 在开发中UI布局是我们都会遇到的问题&#xff0c;随着UI越来越多&#xff0c;布局的重复性、复杂度也会随之增长。 相信大家经常听到include、merge、ViewStub这样的标签&#xff0c;官方也提到这三种布局可用于布局的优化。今天就介绍下这三种布局的使用&#xff0c;记…

SRv6项目实践(一):环境与工具介绍

在一切开始之前&#xff0c;首先介绍一下我们要做什么&#xff0c;做这个要有什么基础&#xff0c;以及实现的环境 1&#xff0c;实验目标与实验基础 我们要在图下图所示的拓扑中&#xff0c;完成在如以下拓扑所示的网络中&#xff0c;配合ONOS实现基本的L2L3转发以及SRv6&am…