前端需要去了解的nodejs知识(工具模块)
nodejs中有许多在框架中常用而我们又不知道的工具模块,本文介绍下这几个工具模块,算是自己的一个知识回顾吧。UtilNode.js 的工具模块常用的判断属性,在util.types对象isDate:判断是否是日期格式的变量isAnyArrayBuffer:判断是否是bufferisAsyncFunction:判断函数是否是异步的let util = require('util');
// types: 判断变量/函数的一些类型
const {isAnyArrayBuffer,isAsyncFunction,isDate} = util.types
// isDate
const is_date = isDate(new Date())
const is_date2 = isDate('2022-09-01')
console.log('is_date2: ', is_date2);
console.log('is_date: ', is_date);
// isAnyArrayBuffer
const isBuff1 = isAnyArrayBuffer('buffer')
console.log('isBuff1: ', isBuff1);
const isBuff2 = isAnyArrayBuffer(new ArrayBuffer(14))
console.log('isBuff2: ', isBuff2);
// isAsyncFunction
const f2 = async function function2(){}
const f1 = function function1(){}
const isAsyncFunc = isAsyncFunction(f1)
const isAsyncFunc2 = isAsyncFunction(f2)
console.log('isAsyncFunc2: ', isAsyncFunc2);
console.log('isAsyncFunc: ', isAsyncFunc);常用的方法和属性format:格式化字符串inspect: 将对象转为字符串isDeepStrictEqual:判断两个字符是否强相等,相当于===deprecate:将函数包装为弃用// inspect
const obj = {name:'inspect',date:'2022-09-01'}
const str = util.inspect(obj)
console.log('str: ', str);
// 格式化字符串util.format(arg1,arg2,arg3,arg4)
const str2 = util.format('%s:%s','12','34','56')
console.log('str2: ', str2);
// deprecate
util.deprecate(()=>{
console.log('this is a deprecate func')
})
// isDeepStrictEqual
const v1 = '2'
const v2 = 2;
const isEqual = util.isDeepStrictEqual(v1,v2)
console.log('isEqual: ', isEqual);
console.log(v1 == v2);
console.log(v1 === v2);DNSNode.js DNS 模块用于解析域名DNS(Domain Name System): 域名系统、组成:他是由解析器和域名服务器组成作用:域名解析,将域名转换成IP地址,将IP地址转换成域名列表nodejs中DNS支持域名和对应IP地址的相互解析,主要代码如下:let dns = require("dns");
//lookup(底层系统工具进行):将域名(比如 'runoob.com')解析为第一条找到的记录 A (IPV4)或 AAAA(IPV6)。
const hostname = "www.runoob.com";
dns.lookup(hostname, function (err, address, famliy) {
if (!err) {
console.log(hostname + "绑定的IP地址为:" + address);
}
});
//lookupService:实现给定的ip地址和端口号,解析为对应的域名
dns.lookupService("104.20.23.46", 80, (err, hostname, service) => {
if (err) {
console.log(err);
}
console.log("主机:" + hostname);
console.log("协议:" + service);
});
//resolve:使用网络域名系统
dns.resolve("nodejs.org", (err, address) => {
if (err) {
return;
}
console.log('resolve address: ', address);
});
// reverse:反向解析 IP 地址,指向该 IP 地址的域名数组。
const ip = "192.30.252.130";
dns.reverse(ip, function (err, hostnames) {
if (!err) {
console.log(ip + "IP绑定的语言数组为:" + hostnames);
} else {
console.log(err);
}
});
// 返回当前正在使用的ip地址
const servers = dns.getServers();
console.log("current server ip address: ", servers);OSNode.js OS 模块提供了一些基本系统操作函数常用的方法和属性networkInterfaces获取网络信息cpus:获取系统的CPU内核细腻,返回个数组totalmem:系统总共内存容量freemem:系统空余内存变量hostname:系统主机名version: 系统内核版本的字符串const os =require('os');
console.log('系统所有内存变量为(单位M):',os.totalmem()/1024/1024);
console.log('系统空余内存变量为(单位M):',os.freemem()/1024/1024);
console.log('系统主机名:',os.hostname());
console.log('系统主机内核版本:',os.version());platform: 主机操作系统平摊type: 主机的操作系统平台名称,可能的值为'aix'、'darwin'、'freebsd'、'linux'、'openbsd'、'sunos'、以及 'win32'。uptime: 操作系统正常运行时间console.log('主机的平台:',os.platform());
console.log('主机的平台名称:',os.type());
console.log('主机的x正常运行时间:',os.uptime()/3600/24);Pathnodejs用来处理文件路径的工具模块,主要处理绝对路径,相对路径常用的方法和属性const path = require('path')
//属性- 平台路径的分隔符
const sep =path.sep;
console.log('sep: ', sep);
//属性- 分隔符获取
const delimiter = path.delimiter;
console.log('delimiter: ', delimiter);
//属性- 提供上述 path 的方法,不过总是以 win32 兼容的方式交互。
const win32 = path.win32;
// console.log('win32: ', win32);
// resolve参数解析为绝对路径
const r1 = path.resolve(__dirname,'../');
console.log('r1: ', r1);
// join参数拼接为一个路径
const j1 = path.join(r1,'http/app.js')
console.log('j1: ', j1);
// path.relative(from, to)用于将绝对路径转为相对路径,返回从 from 到 to 的相对路径(基于当前工作目录)
const r2 = path.relative(j1,'http/app.js')
console.log('rl: ', r2);
// isAbsolute判断是否是绝对路径
const isAbs1 = path.isAbsolute(r2)
console.log('isAbs1: ', isAbs1);
const isAbs2 = path.isAbsolute(j1)
console.log('isAbs2: ', isAbs2);
// path.dirname(p):返回路径中代表文件夹的部分,同 Unix 的dirname 命令类似。
const dir = path.dirname(j1)
console.log('dir: ', dir);
// path.basename:返回路径中的最后一部分。同 Unix 命令 bashname 类似。
const basename = path.basename(j1)
console.log('basename: ', basename);
// path.extname(p): 返回路径中文件的后缀名,即路径中最后一个'.'之后(包含'.')的部分。如果一个路径中并不包含'.'或该路径只包含一个'.' 且这个'.'为路径的第一个字符,则此命令返回空字符串。
const extname = path.extname(j1);
console.log('extname: ', extname);
// path.parse(pathString):返回路径字符串的对象,与path.format相反。
const pathObj = path.parse('D:\\demo\\demo\\nodejs\\http\\app.js')
console.log('pathObj: ', pathObj);
// path.format(pathObject):从对象中返回路径字符串,和 path.parse 相反。
const pathStr = path.format(pathObj)
console.log('pathStr: ', pathStr);总结nodejs中的util path os dns是我们开发web服务会常用的几个模块,再次做一了解很有必要。
前端需要去了解的nodejs知识(dgram)
对于前端开发,http服务是我们最长接触的通信服务,偶尔也会用到一些类似于聊天框的长链接应用,这些应用都不是基于HTTP开发的,HTTP是是无状态的短连接,说到长连接是不是首先会想到TCP,TCP是有状态的长连接协议。TCP和HTTP都是有连接的意思就是通信前需要建立连接,但是在计算机网络世界还有种无连接的协议UDP,下面我们就来了解下TCP在nodejs中的应用。dgramUDP(用户数据报协议)协议对于UDP,我们可以结合TCP一起来看,他们之间的区别以及共同之处。UDP是无连接的用户数据报协议UDP是不可靠的传输,数据在传输过程中可能会丢失UDP的传输速度是更快的UDP的连接是可以一对一,一对多,多对多,多对一的UDP应用场合:流媒体或游戏之类对数据准确性要求不是很高的应用,例如我们常用的视频通话,目前发展比较好的智能家居也是基于UDP在传输协议nodejs中的dgramnodejs中dgram的UDP传输共有三种,分别为:单播,组播,广播单播:服务端向单个客户端发送数据const dgram =require('dgram');
const server = dgram.createSocket('udp4');
server.on('listening',()=>{
var address=server.address();
console.log('listening on:'+address.address+':'+address.port)
})
// 单播发送数据
server.on('message',(message,remote)=>{
console.log('收到了你的消息: ', message.toString());
const address = remote.address;
console.log('remote.address: ', remote.address);
const port = remote.port;
console.log('remote.port: ', remote.port);
// server.send('我已经收到你们发送的消息了!',port,address)
})
server.on('error',()=>{
console.log('服务其出错了');
})
//绑定8888端口
server.bind(4000)广播、组播:通过ip和子网掩码计算出广播地址const dgram =require('dgram');
const server = dgram.createSocket('udp4');
const multicastAddr = "*******"
server.on('listening',()=>{
var address=server.address();
//设置广播发送
server.setBroadcast(true);
server.setMulticastTTL(128);
setInterval(()=>{
console.log('发送消息')
server.send('我已经上线了!',5000,'广播地址**')
server.send('大家好啊,我是服务端组播消息', 8061, multicastAddr);
},3000)
console.log('listening on:'+address.address+':'+address.port)
})
server.on('error',()=>{
console.log('服务其出错了');
})
//绑定8888端口
server.bind(4000)启动客户端服务const dgram =require('dgram');
const client = dgram.createSocket('udp4');
// 需要和服务端设置的相同
const multicastAddr = "*******"
client.on("listening", () => {
console.log("listening");
//设置客户的组播地址
client.addMembership(multicalAddress)\
})
client.on('message',(msg)=>{
console.log('我收到了服务端发送的消息!')
console.log('msg: ', msg.toString());
client.send(`hello,I am client`,4000,'localhost');
})
client.on("close", () => {
console.log("socket已经关闭");
})
client.bind(5000,"127.0.0.1")总结UDP协议最经典的应用应该就是微信端视频聊天了,视频聊天追求的是时效性,而TCP为了保证数据的准确性会在进行回复,重传,网络探测等等一系列的控制,这些都影响了传输的时效性,因此对于追求快速传输且对数据准确性要求不太高的应用UDP就是更好的选择。UDP在我们前端开发中其实接触的比较少,但我们可以和TCP一起了解,这两个协议许多都是相反的。一起学习的话应该更容易掌握。
前端需要去了解的nodejs知识(net)
对于前端开发,http服务是我们最长接触的通信服务,偶尔也会用到一些类似于聊天框的长链接应用,这些应用都不是基于HTTP开发的,HTTP是是无状态的短连接,说到长连接是不是首先会想到TCP,TCP是有状态的长连接协议。TCP和HTTP都是有连接的意思就是通信前需要建立连接,但是在计算机网络世界还有种无连接的协议UDP,下面我们就来了解下TCP在nodejs中的应用。netTCP(传输控制协议)协议TCP协议的特点如下:TCP是面向连接的传输层协议TCP是可靠的传输方式,可确保数据不会丢失TCP是一对一的连接的TCP可提供全双工通信(通信双方可以任意时候发送数据)TCP数据传输是面向字节流的TCP是三次握手的连接方式,四次挥手的断开连接方式三次握手:客户端发送连接请求,服务端同意连接请问并返回到客户端,客户端建立与服务端的连接四次挥手,TCP释放连接的流程大致如下:Client告诉Server不会再发送数据=》Server告诉Client知道了等我发送完当前数据就关闭=》Server端发送完当前数据释放连接,等待Client确认=》Client确认释放连接,TCP连接关闭TCP应用场合:网页浏览,聊天程序,邮件等需要保证数据准确性的应用nodejs中的net使用Node.js Net 模块提供了一些用于底层的网络通信的小工具,包含了创建服务器/客户端的方法。服务端,主要流程为:创建服务,监听连接,发送数据,连接断开const net = require("net");
/**
* 服务端创建连接服务
*/
const server = net.createServer((socket) => {
//监听关闭客户端连接
socket.on("end", () => {
console.log("客户端关闭连接!");
});
//收到的数据是二进制流数据
socket.on("data", (data) => {
console.log("data: ", data.toString());
});
//向所有的客户端发送数据
socket.write("hello, I am server!", () => {});
});
// 设置同时最大连接数
server.setMaxListeners = 99;
server.on("connection", () => {
console.log("新的客户端已接入");
});
server.listen(4000, () => {
console.log("server is listening");
});客户端,主要流程为:连接服务,监听服务端数据,向服务端发送数据,连接断开const net = require('net');
const client = net.createConnection(4000,'localhost')
//监听服务发来的数据
client.on('data',(data)=>{
console.log('客户端:已成功连接服务端!');
console.log('服务端发来的数据----: ', data.toString());
})
client.on('connect', function(){
console.log('客户端:已经与服务端建立连接');
});
client.on('close', function(data){
console.log('客户端:连接断开');
});
let index = 0;
setInterval(()=>{
if(index === 9){
//断开与服务器的连接
client.end('10条数据已经发送完喽!')
return
}
//客户端给服务端发送数据
client.write(`向客户端发送第${index}条数据`)
index ++
},1000)
// client.end(JSON.stringify({name:"wo shi bao bao a!"}))总结对于TCP协议最常用的应该就是实时聊天系统,另外基于HTTP协议的应用我们都可以认为底层协议是TCP应为HTTP是建立在TCP的基础之上的,理解TCP对于我们前端开发至关重要。
前端需要去了解的nodejs知识(http)
http超文本传输协议,稍微有点网络知识的人都晓得这个名词,那nodejs中的http和他有什么关系呢?Nodejs中的http是实现网络传输的基础模块,HTTP协议HTTP(超文本传输协议),是应用层中的数据传输协议,是万维网数据通信的基础。HTTP的协议在应用层的主要特征如下:HTTP协议中必须同时具备客户端和服务端。基于 TCP/IP 通信协议来传递数据。HTTP是无连接(区别于socket),无连接的含义是限制每次连接只处理一个请求,服务器处理完客户的请求,并收到客户的应答后,即断开连接,采用这种方式可以节省传输时间。HTTP 是无状态(需要引入缓存的原因),HTTP对于事务处理是没有记忆能力的,后续的请求是无法获取前面请求的任何信息的。HTTP 是媒体独立的(对于传输的数据是无限制的),只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。Nodejs http模块网上搜索到一张很形象的图,描述了http和TCP/IP之间的关系,由图可看出HTTP和TCP/IP的整体作用是保证数据在客户端(发起请求方)和服务端(接受请求方)的传输。两者间的区别:TCP/IP传输的报文是字节(二进制数据),HTTP传输的是超文本数据(字符)TCP是作用于传输层的,HTTP是作用于应用层的,HTTP请求时通过 TCP 协议建立起连接服务器的通道HTTP 是无状态的短连接,而 TCP 是有状态的长连接TCP定义的是数据传输和连接方式的规范,HTTP是应用层协议,定义的是传输数据的内容的规范注:这里为何要了解下TCP呢,因为HTTP协议是建立在TCP基础上的,如果对TCP协议没有一定的了解是无法真正的明白HTTP的传输流程的。HTTP的使用HTTP模块主要分为创建服务HTTP.createServer和创建请求HTTP.requestHTTP服务创建:nodejs的http模块能够创建一个http服务,const http = require('http')
// createServer可以用回调函数实现对客户端请求对监听,也可以通过request事件的监听来实现
const server = http.createServer((request,response)=>{
})
// 监听request事件
server.on("request",(request,response)=>{
})
// 指定通信端口
server.listen(8080, function () {
console.log('server running at http://localhost:8080')
})HTTP服务回调函数有request和reponse组成:request:解析客户端的请求常用属性及方法:url(请求路径) method(请求方法)headers(头部)url:请求的路径,可以根据URL设置出路由模式,express的就是基于此设置的methoe:请求的方式分为,post get delete put patchheaders: 请求的头部,客户单的cookie,数据传输的类型等都放在header中data事件:createServer想要获取请求数据体需要监听data事件req.on('data',function(data){
console.log('data: ', data);
});response:相应客户端请求,常用属性及方法如下:end:res.end()setHeader(name,content),可以设置单个header属性,可以多次设置destory:取消返回statusCode:设置返回的状态码,如200 404 400 500等statusMessage:设置状态码对应返回的信息writeHead:可以同时设置statusCode statusMessage 和多个header属性res.writeHead(200,"success", {"Content-type" : "text/html"});HTTP请求的创建,Nodejs的http模块不仅仅能作为服务器来接受请求,也能作为客户端来发送请求。const http = require('http');
const options = {
port: 3333,
hostname: 'localhost',
path: '/demo',
method: 'POST',
headers: {
"Content-Type":'text/html'
}
}
const req = http.request(options,(res)=>{
console.log(`statusCode: ${res.statusCode}`);
res.on('data', data => {
console.log(data)
});
})
req.end()HTTP请求主要有请求参数和返回值组成:options:请求参数主要有以下属性method:请求服务端的方法path:请求的路径port:请求的端口hostname:请求的主机名headers:请求时header上的内容response:请求后的返回值data事件监听res.on('data', data => {
console.log(data)
});总结对于Nodejs HTTP模块的总结就到这里了,此次重新学习了下HTTP的API,对于API的了解是比较简单,只要经常使用能够掌握,但是对于HTTP的传输流程需要我们去查阅许多计算机网络的相关知识,其中TCP/IP是必须要了解的,扩散性学习能够更快的掌握新知识也能从已有的知识的推导出更多相关的知识。
学点Linux命令没坏处(网络)
前言本章一起了解下Linux中网络基础,分别从一下几个方面来学习:网络的状态 网络的配置 网络监控 网络连接。Linux中网络命令显示查询,在linux查询网络状态的有以下命令:ifconfig(像是网络信息) route(显示路由表) netstat(显示网络状态) ss(显示网络状态) arp(arp命令用于操作本机的arp缓存区,它可以显示arp缓存区中的所有条目、删除指定的条目或者添加静态的IP地址与MAC地址的对应关系。) nmap(网络探测工具,非内置命令需要安装) nslookup(常用的域名解析查询工具。) dig(域名查询工具) host (域名解析查询工具。)//ifconfig:配置或显示网络接口信息(List of possible hardware types:)
[root@localhost ~]# ifconfig #<===查看机器上所有激活的网卡
enp0s25: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.10 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::a9d2:ba42:8306:8177 prefixlen 64 scopeid 0x20<link>
inet6 240e:388:8221:2c00:1cd8:fd91:cb44:ec62 prefixlen 64 scopeid 0x0<global>
ether 04:7d:7b:39:95:ab txqueuelen 1000 (Ethernet)
RX packets 2435833 bytes 535444996 (510.6 MiB)
RX errors 2 dropped 0 overruns 0 frame 1
TX packets 2121493 bytes 318310278 (303.5 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 20 memory 0xf4600000-f4620000
#===>ifconfig + 网卡名:显示指定网卡
#===>ifconfig + 网卡名 + up/down:启动、关闭网卡
#===>ifconfig + 网卡名 + ip地址:修改网卡ip地址
#===>ifconfig + 网卡名 + hw + ether + 网卡地址:修改网卡地址
//route 显示或管理路由表,主要管理的是静态路由
[root@localhost demo]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default gateway 0.0.0.0 UG 100 0 0 enp0s25
192.168.1.0 0.0.0.0 255.255.255.0 U 100 0 0 enp0s25
//netstat 查看网络状态 -r -g -s -n -a(显示处于非监听/监听状态的socket信息)
[root@localhost demo]# netstat
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 localhost.localdo:27017 121.4.59.78:58206 ESTABLISHED
tcp 0 0 localhost.localdo:27017 121.4.59.78:58192 ESTABLISHED
....
//netstat命令用于显示本机网络的连接状态、运行端口和路由表等信息。
[root@VM-12-10-centos ~]# netstat -an #<====显示所有的连接信息>
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 10.0.12.10:40340 169.254.0.55:8080 TIME_WAIT
...
// 以上命令语句的作用为显示所有TCP和UDP正在监听的连接信息。
[root@VM-12-10-centos ~]# netstat -lntup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN 228480/mongod
...
//显示路由表
[root@VM-12-10-centos ~]# netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 10.0.12.1 0.0.0.0 UG 0 0 0 eth0
10.0.12.0 0.0.0.0 255.255.252.0 U 0 0 0 eth0
//ss命令是类似并将取代netstat的工具,它能用来查看网络状态信息,包括TCP、UDP连接、端口等。它的优点是能够显示更多更详细的有关网络连接状态的信息,而且比netstat更快速更高效。
//显示所有socket连接
[root@VM-12-10-centos ~]# ss -an
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
nl UNCONN 0 0 0:981585547 *
nl UNCONN 0 0
...
//统计当前的established closed orphaned和waiting的TCP socket数量
[root@VM-12-10-centos ~]# ss -s
Total: 219
TCP: 34 (estab 28, closed 0, orphaned 0, timewait 0)
Transport Total IP IPv6
RAW 1 0 1
UDP 3 2 1
TCP 34 5 29
INET 38 7 31
...
//arp是查看缓存信息(arp缓存就是IP地址和MAC地址关系缓存列表)的详细信息 详细信息2
//在局域网中,当主机或其它三层网络设备有数据要发送给另一台主机或三层网络设备时,需要知道对方的网络层地址(即IP地址)。但是仅有IP地址是不够的,因为IP报文必须封装成帧才能通过物理网络发送,因此发送方还需要知道接收方的物理地址(即MAC地址),这就需要一个通过IP地址获取物理地址的协议,以完成从IP地址到MAC地址的映射。地址解析协议ARP即可实现将IP地址解析为MAC地址。
//arp:地址解析协议(Address Resolution Protocol),主要功能是根据IP地址获取物理地址
[root@VM-12-10-centos ~]# arp -n
Address HWtype HWaddress Flags Mask Iface
10.0.12.1 ether fe:ee:5e:4d:d7:bb C eth0nmap:功能全面的端口扫描工具,此外还具备寻找目标网络中的在线主机文档地址,常用的扫描如下SYN扫描,使用频率最高的扫描选项:SYN扫描,又称为半开放扫描,它不打开一个完全的TCP连接,执行得很快,nmap -sS ***/24ping扫描,用ping的方式检查网络上哪些主机正在运行。 nmap -sP ***/24[root@zz ~]# nmap 192.168.1.10 #<====扫描主机开放的服务>
Starting Nmap 6.40 ( http://nmap.org ) at 2022-07-22 19:18 CST
Nmap scan report for 192.168.1.10
Host is up (0.000017s latency).
Not shown: 996 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3306/tcp open mysql
8080/tcp open http-proxy
Nmap done: 1 IP address (1 host up) s
[root@zz ~]# nmap -p 8080 192.168.1.10 #<====指定端口扫描
Starting Nmap 6.40 ( http://nmap.org ) at 2022-07-22 19:24 CST
Nmap scan report for 192.168.1.10
Host is up (0.00013s latency).
PORT STATE SERVICE
8080/tcp open http-proxy
Nmap done: 1 IP address (1 host up) scanned in 0.29 seconds
[root@zz ~]# nmap -sP 192.168.123.1/24
Starting Nmap 6.40 ( http://nmap.org ) at 2022-07-22 19:30 CST
Nmap done: 256 IP addresses (0 hosts up) scanned in 206.24 secondsnslookup dig host这三个都是域名查询工具,区别如下:nslookup可以以交互的方式查询 dig用于测试dns系统(不会查询host)host以更简洁的方式显示查询结果// nslookup交互模式
[root@zz ~]# nslookup
> www.baidu.com
Server: 192.168.1.1
Address: 192.168.1.1#53
Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com.
Name: www.a.shifen.com
Address: 180.101.49.12
Name: www.a.shifen.com
Address: 180.101.49.11
[root@zz ~]# nslookup
> set type=MX #<==== set用来设置查询方式 MX表示邮件交换记录,邮件交换记录 (MX record)是域名系统(DNS)中的一种资源记录类型>
> www.baidu.com
Server: 192.168.1.1
Address: 192.168.1.1#53
Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com.
Authoritative answers can be found from:
a.shifen.com
origin = ns1.a.shifen.com
mail addr = baidu_dns_master.baidu.com
serial = 2207240004
refresh = 5
retry = 5
expire = 2592000
minimum = 3600
>
[root@zz ~]# nslookup www.baidu.com #<====非交互方式查询>
Server: 192.168.1.1
Address: 192.168.1.1#53
Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com.
Name: www.a.shifen.com
Address: 180.101.49.11
Name: www.a.shifen.com
Address: 180.101.49.12
[root@zz ~]# nslookup -ty=ptr 202.96.128.166 #<===反向域名解析 ptr表示反向域名解析>
Server: 192.168.1.1
Address: 192.168.1.1#53
Non-authoritative answer:
166.128.96.202.in-addr.arpa name = cache-b.guangzhou.gd.cn.
Authoritative answers can be found from:
[root@zz ~]# dig www.baidu.com #<====域名解析>
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.9 <<>> www.baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31412
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;www.baidu.com. IN A
;; ANSWER SECTION:
www.baidu.com. 600 IN CNAME www.a.shifen.com.
www.a.shifen.com. 600 IN A 180.101.49.11
www.a.shifen.com. 600 IN A 180.101.49.12
;; Query time: 4 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Sun Jul 24 16:42:34 CST 2022
;; MSG SIZE rcvd: 90
[root@zz ~]# dig -x 101.200.195.98 #<=== dig -x ip 反向域名解析>
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.9 <<>> -x 101.200.195.98
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 4919
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;98.195.200.101.in-addr.arpa. IN PTR
;; AUTHORITY SECTION:
200.101.in-addr.arpa. 300 IN SOA rdns1.alidns.com. dnsmgr.alibaba-inc.com. 2015011391 1800 600 1814400 300
;; Query time: 24 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Sun Jul 24 16:52:07 CST 2022
;; MSG SIZE rcvd: 127
[root@zz ~]# host www.baidu.com #<==== host + domain 更简单的显示查询内容>
www.baidu.com is an alias for www.a.shifen.com.
www.a.shifen.com has address 180.101.49.11
www.a.shifen.com has address 180.101.49.12
//ping命令可用于测试主机之间网络的连通性。执行ping命令会使用ICMP传输协议,发出要求回应的信息,若远端主机的网络功能没有问题,就会回应该信息,因而可得知该主机运作正常。
[root@zz ~]# ping 192.168.1.12
PING 192.168.1.12 (192.168.1.12) 56(84) bytes of data.
64 bytes from 192.168.1.12: icmp_seq=1 ttl=64 time=4.16 ms
64 bytes from 192.168.1.12: icmp_seq=2 ttl=64 time=2.92 ms
64 bytes from 192.168.1.12: icmp_seq=3 ttl=64 time=2.71 ms
64 bytes from 192.168.1.12: icmp_seq=4 ttl=64 time=3.22 ms
64 bytes from 192.168.1.12: icmp_seq=5 ttl=64 time=2.72 ms
[root@zz ~]# ping -c 3 -i 3 192.168.1.12 #<==== -c:ping次数 -i:每次ping的间隔
PING 192.168.1.12 (192.168.1.12) 56(84) bytes of data.
64 bytes from 192.168.1.12: icmp_seq=1 ttl=64 time=5.49 ms
64 bytes from 192.168.1.12: icmp_seq=2 ttl=64 time=3.64 ms
64 bytes from 192.168.1.12: icmp_seq=3 ttl=64 time=3.13 ms
--- 192.168.1.12 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 6007ms
rtt min/avg/max/mdev = 3.139/4.092/5.492/1.012 ms注:ping命令的输出信息中含有TTL值。TTL(Time To Life)称为生存期,它是ICMP报文在网络上的存活时间。不同的操作系统发出的ICMP报文的生存期各不相同,常见的生存期为32、64、128和255等。TTL值反映了ICMP报文所能够经过的路由器数目,每经过一个路由器,路由器都会将其数据包的生存期减去1,如果TTL值变为0,则路由器将不再转发此报文。 traceroute命令用于显示网络数据包传输到指定主机的路径信息,追踪数据传输路由状况。默认数据包大小是60字节(IPv4)或80字节(IPv6),用户可另行设置。它与Windows下的tracert命令类似。[root@zz ~]# traceroute juejin.cn
traceroute to juejin.cn (61.174.42.228), 30 hops max, 60 byte packets
1 gateway (192.168.1.1) 7.137 ms 7.088 ms 7.012 ms
2 1.72.65.222.broad.xw.sh.dynamic.163data.com.cn (222.65.72.1) 10.522 ms 10.495 ms 11.113 ms
3 61.152.54.133 (61.152.54.133) 9.409 ms 9.369 ms 9.305 ms
4 101.95.88.142 (101.95.88.142) 9.747 ms 61.152.25.202 (61.152.25.202) 9.198 ms 61
.....
8 * * *注:记录按序列号从1开始,每个记录就是一跳,每跳表示一个网关,我们看到每行有3个时间,单位是ms,其实就是-q的默认参数值为3。探测数据包向每个网关发送3个数据包之后,网关响应并返回的时间。 有时我们traceroute一台主机时,会看到有一些星号。出现这样的情况,可能是因为网络设备封掉或丢弃了返回的信息,所以我们得不到返回的时间。arping命令是用于发送arp请求到一个相邻主机的工具,arping使用arp数据包检查局域网内所有设备的硬件地 址。[root@zz ~]# arping -f 192.168.1.12 #<=== -f 表示第一次收到返回就结束了
ARPING 192.168.1.12 from 192.168.1.10 enp0s25
Unicast reply from 192.168.1.12 [64:90:C1:35:D0:2E] 5.241ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)配置网络(启用、禁用网络接口、配置路由、激活、禁用),主要有以下命令:ifconfig(配置网络)ifup(激活网络接口) ifdown(禁用网络接口) ip(网络配置工具)//ifup+网卡名:激活网络接口
[root@zz ~]# ifup enp0s25
//ifdown + 网卡名:禁用网络接口
[root@zz ~]# ifdown enp0s25网络监听:tcpdump(监听网络流量)tcpdump命令是一个截获网络数据包的包分析工具。tcpdump可以将网络中传送的数据包的“头”完全截获下来以提供分析。[root@zz ~]# tcpdump #<====查看所有网络流量>
tcpdump: ve ....
10 packets captured
11 packets received by filter
0 packets dropped by kernel
[root@zz ~]# tcpdump -i enp0s25 port 8080 #<====指定端口监听>
tcpdump: verbose output suppressed, use -v or -vtcpdump是一个非常强大并且好用的命令,这是只做简单的介绍,后续还要在实践中多多练习。邮件相关:mail(发送和接收邮件) mailq(显示邮件传输队列),mail命令是命令行的电子邮件发送和接收的工具。mail命令是个软链接,真实的程序文件是mailx: mail命令会默认使用本地postfix(sendmail)发送邮件,这就要求本地的机器必须安装和启动相关服务,这样不仅配置非常麻烦,而且还会带来不必要的资源占用。还有一个问题,很多时候,所发送的邮件会被视为垃圾邮件[root@zhaokai ~]# mailq
Mail queue is empty
[root@zhaokai ~]# mailq -v
postqueue: name_mask: all
...
[root@zhaokai postfix]# mail -s "Hello qq" zhaokai1155@outlook.com #<====mail -s指定邮件主题,知否输入邮件内容,按Ctrl + D发送
this is a mail;
EOT
ZYNQ裸板:AXIDMA篇(简单模式)
前言 DMA(Direct Memory Access,直接存储器访问)是计算机科学中的一种内存访问技术。它允许某些计算机内部的硬件子系统可以独立地直接读写系统内存,而不需中央处理器( CPU)介入处理。 DMA 是一种快速的数据传送方式, 通常用来传送数据量较多的数据块 使用 DMA时, CPU 向 DMA 控制器发出一个存储传输请求, 这样当 DMA 控制器在传输的时候, CPU 执行其它操作,传输操作完成时 DMA 以中断的方式通知 CPU。 为了发起传输事务, DMA 控制器必须得到以下数据:• 源地址 — 数据被读出的地址• 目的地址 — 数据被写入的地址• 传输长度 — 应被传输的字节数DMA 存储传输的过程如下:为了配置用 DMA 传输数据到存储器,处理器发出一条 DMA 命令DMA 控制器把数据从外设传输到存储器或从存储器到存储器,而让 CPU 腾出手来做其它操作。数据传输完成后,向 CPU 发出一个中断来通知它 DMA 传输可以关闭了。ZYNQ 提供了两种 DMA,一种是集成在 PS 中的硬核 DMA,另一种是 PL 中使用的软核 AXI DMA IP。在 ARM CPU 设计的过程中,已经考虑到了大量数据搬移的情况,因此在 CPU 中自带了一个 DMA 控制器 DAMC,这个 DAMC 驻留在 PS 内,而且必须通过驻留在内存中的 DMA 指令编程,这些程序往往由CPU 准备,因此需要部分的 CPU 参与。 DMAC 支持高达 8 个通道,所以多个 DMA 结构的核可以挂在单个DMAC 上。 DAMC 与 PL 的连接是通过 AXI_GP 接口,这个接口最高支持到 32 位宽度,这也限制了这种模式下的传输速率,理论最高速率为 600MB/s。这种模式不占用 PL 资源,但需要对 DMA 指令编程,会增加软件的复杂性。为了获取更高的传输速率,可以以空间换时间,在 PL 中添加 AXI DMA IP 核,并利用 AXI_HP 接口完成高速的数据传输。原子将各个接口方式的比较做了表格,很是详细 可见通过 PL 的 DMA 和 AXI_HP 接口的传输适用于大块数据的高性能传输,带宽高。 下面我们简单的介绍下 PL 的 DMA,即 AXI DMA IP 核。 AXI Direct Memory Access( AXI DMA) IP 内核在 AXI4 内存映射和 AXI4-Stream IP 接口之间提供高带宽直接储存访问。其可选的 scatter gather 功能还可以从基于处理器的系统中的中央处理单元( CPU)卸载数据移动任务。初始化、 状态和管理寄存器通过 AXI4-Lite 从接口访问。核心的功能组成如下图所示: AXI DMA 用到了三种总线, AXI4-Lite 用于对寄存器进行配置, AXI4 Memory Map 用于与内存交互,又分为 AXI4 Memory Map Read 和 AXI4 Memory Map Write 两个接口,一个是读一个是写。 AXI4 Stream 接口用于对外设的读写,其中 AXI4 Stream Master( MM2S, Memory Map to Stream)用于对外设写, AXI4-Stream Slave(S2MM, Stream to Memory Map)用于对外设读。总之,在以后的使用中需要知道 AXI_MM2S 和AXI_S2MM 是存储器端映射的 AXI4 总线,提供对存储器( DDR3)的访问。 AXIS_MM2S 和 AXIS_S2MM是 AXI4-streaming 总线,可以发送和接收连续的数据流,无需地址。 AXI DMA 提供 3 种模式,分别是 Direct Register 模式、 Scatter/Gather 模式和 Cyclic DMA 模式,这里我们简单的介绍下常用的 Direct Register 模式和 Scatter/Gather 模式。 Direct Register DMA 模式也就是 Simple DMA。 Direct Register 模式提供了一种配置,用于在 MM2S 和S2MM 通道上执行简单的 DMA 传输,这需要更少的 FPGA 资源。 Simple DMA 允许应用程序在 DMA 和Device 之间定义单个事务。它有两个通道:一个从 DMA 到 Device,另一个从 Device 到 DMA。应用程序必须设置缓冲区地址和长度字段以启动相应通道中的传输。 Scatter/Gather DMA 模式允许在单个 DMA 事务中将数据传输到多个存储区域或从多个存储区域传输数据。它相当于将多个 Simple DMA 请求链接在一起。 SGDMA 允许应用程序在内存中定义事务列表,硬件将在应用程序没有进一步干预的情况下处理这些事务。在此期间,应用程序可以继续添加更多工作以保持硬件工作。用户可以通过轮询或中断来检查事务是否完成。 SGDMA 处理整个数据包( 被定义为表示消息的一系列数据字节)并允许将数据包分解为一个或多个事务。例如,采用以太网 IP 数据包,该数据包由 14 字节的报头后跟 1 个或多个字节的有效负载组成。使用 SGDMA,应用程序可以将 BD( Buffer Descriptor, 用于描述事务的对象) 指向报头,将另一个 BD 指向有效负载,然后将它们作为单个消息传输。这种策略可以使TCP / IP 堆栈更有效,它允许将数据包标头和数据保存在不同的内存区域,而不是将数据包组装成连续的内存块。 在此次的工程中暂时用不到SG模式,如果用sata这些的话估计得用到了,正常情况下简单模式还是够用的下面做一个简单的AXIDMA初始化和收发demo测试头文件如下#ifndef SRC_XDMA_DRIVER_H_
#define SRC_XDMA_DRIVER_H_
#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#ifdef XPAR_UARTNS550_0_BASEADDR
#include "xuartns550_l.h" /* to use uartns550 */
#endif
#ifdef XPAR_INTC_0_DEVICE_ID
#include "xintc.h"
#else
#include "xscugic.h"
#endif
#include "xgpiops.h"
/************************** Constant Definitions *****************************/
/*
* Device hardware build related constants.
*/
#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID
#ifdef XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#elif XPAR_MIG7SERIES_0_BASEADDR
#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR
#elif XPAR_MIG_0_BASEADDR
#define DDR_BASE_ADDR XPAR_MIG_0_BASEADDR
#elif XPAR_PSU_DDR_0_S_AXI_BASEADDR
#define DDR_BASE_ADDR XPAR_PSU_DDR_0_S_AXI_BASEADDR
#endif
#ifndef DDR_BASE_ADDR
#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \
DEFAULT SET TO 0x01000000
#define MEM_BASE_ADDR 0x01000000
#else
#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000)
#endif
#ifdef XPAR_INTC_0_DEVICE_ID
#define RX_INTR_ID XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID
#define TX_INTR_ID XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID
#else
//#define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
//#define TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID
#endif
#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000)
#define TX_BUFFER_BASE1 (MEM_BASE_ADDR + 0x00101000)
#define TX_BUFFER_BASE2 (MEM_BASE_ADDR + 0x00102000)
#define TX_BUFFER_BASE3 (MEM_BASE_ADDR + 0x00103000)
#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000)
#define RX_BUFFER_BASE1 (MEM_BASE_ADDR + 0x00301000)
#define RX_BUFFER_BASE2 (MEM_BASE_ADDR + 0x00302000)
#define RX_BUFFER_BASE3 (MEM_BASE_ADDR + 0x00303000)
#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF)
#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID
#else
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#endif
#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC XIntc
#define INTC_HANDLER XIntc_InterruptHandler
#else
#define INTC XScuGic
#define INTC_HANDLER XScuGic_InterruptHandler
#endif
extern XAxiDma AxiDma; /* Instance of the XAxiDma */
extern XAxiDma AxiDma1; /* Instance of the XAxiDma */
extern XAxiDma AxiDma2; /* Instance of the XAxiDma */
extern XAxiDma AxiDma3; /* Instance of the XAxiDma */
/* Timeout loop counter for reset
*/
#define RESET_TIMEOUT_COUNTER 10000
#define TEST_START_VALUE 0xC
/*
* Buffer and Buffer Descriptor related constant definition
*/
#define MAX_PKT_LEN 0x100
#define NUMBER_OF_TRANSFERS 10
static XGpioPs Gpio; /* The Instance of the GPIO Driver */
/* The interrupt coalescing threshold and delay timer threshold
* Valid range is 1 to 255
*
* We set the coalescing threshold to be the total number of packets.
* The receive side will only get one completion interrupt for this example.
*/
/************* Type Definitions ******************/
/***** Macros (Inline Functions) Definitions **********/
/************* Function Prototypes **************/
#ifndef DEBUG
extern void xil_printf(const char *format, ...);
#endif
#ifdef XPAR_UARTNS550_0_BASEADDR
void Uart550_Setup(void);
#endif
static int CheckData(int Length, u8 StartValue);
//static void TxIntrHandler(void *Callback);
//static void RxIntrHandler(void *Callback);
int dma_init(void);
int dma_8_10b_send(XAxiDma* AxiDmaIns,u8 *wBuffer , unsigned int length);
unsigned int dma_8_10b_recv(XAxiDma* AxiDmaIns,u8 *rBuffer);
static int SetupIntrSystem(INTC * IntcInstancePtr,
XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);
static void DisableIntrSystem(INTC * IntcInstancePtr,
u16 TxIntrId, u16 RxIntrId);
int SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,
u16 GpioIntrId);
static void TxIntrHandler(AxiDma);
static void RxIntrHandler(AxiDma);
/************** Variable Definitions ****************/
/*
* Device instance definitions
*/
static INTC Intc; /* Instance of the Interrupt Controller */
/*
* Flags interrupt handlers use to notify the application context the events.
*/
volatile int TxDone;
volatile int DMA0RxDone;
volatile int DMA1RxDone;
volatile int DMA2RxDone;
volatile int DMA3RxDone;
volatile int Error;
#endif /* SRC_XDMA_DRIVER_H_ */
驱动文件如下#include "xdma_driver.h"
XAxiDma AxiDma; /* Instance of the XAxiDma */
XAxiDma AxiDma1; /* Instance of the XAxiDma */
XAxiDma AxiDma2; /* Instance of the XAxiDma */
XAxiDma AxiDma3; /* Instance of the XAxiDma */
#ifdef XPAR_UARTNS550_0_BASEADDR
/*****************************************************************************/
/*
*
* Uart16550 setup routine, need to set baudrate to 9600 and data bits to 8
*
* @param None
*
* @return None
*
* @note None.
*
******************************************************************************/
extern void Uart550_Setup(void)
{
XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR,
XPAR_XUARTNS550_CLOCK_HZ, 9600);
XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR,
XUN_LCR_8_DATA_BITS);
}
#endif
/*****************************************************************************/
/*
*
* This function checks data buffer after the DMA transfer is finished.
*
* We use the static tx/rx buffers.
*
* @param Length is the length to check
* @param StartValue is the starting value of the first byte
*
* @return
* - XST_SUCCESS if validation is successful
* - XST_FAILURE if validation is failure.
*
* @note None.
*
******************************************************************************/
int CheckData(int Length, u8 StartValue)
{
u8 *RxPacket;
int Index = 0;
u8 Value;
RxPacket = (u8 *) RX_BUFFER_BASE;
Value = StartValue;
/* Invalidate the DestBuffer before receiving the data, in case the
* Data Cache is enabled
*/
#ifndef __aarch64__
Xil_DCacheInvalidateRange((UINTPTR)RxPacket, Length);
#endif
for(Index = 0; Index < Length; Index++) {
if (RxPacket[Index] != Value)
{
xil_printf("Data error %d: %x/%x\r\n",
Index, RxPacket[Index], Value);
return XST_FAILURE;
}
Value = (Value + 1) & 0xFF;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/*
*
* This is the DMA TX Interrupt handler function.
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then sets the TxDone.flag
*
* @param Callback is a pointer to TX channel of the DMA engine.
*
* @return None.
*
* @note None.
*
******************************************************************************/
//static void TxIntrHandler(void *Callback)
static void TxIntrHandler(XAxiDma *AxiDma)
{
u32 IrqStatus;
int TimeOut;
//XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(AxiDma, XAXIDMA_DMA_TO_DEVICE);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(AxiDma, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
/*
* If no interrupt is asserted, we do not do anything
*/
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return;
}
/*
* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
Error = 1;
/*
* Reset should never fail for transmit channel
*/
XAxiDma_Reset(AxiDma);
TimeOut = RESET_TIMEOUT_COUNTER;
while (TimeOut) {
if (XAxiDma_ResetIsDone(AxiDma)) {
break;
}
TimeOut -= 1;
}
return;
}
/*
* If Completion interrupt is asserted, then set the TxDone flag
*/
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
TxDone = 1;
}
}
/*****************************************************************************/
/*
*
* This is the DMA RX interrupt handler function
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then it sets the RxDone flag.
*
* @param Callback is a pointer to RX channel of the DMA engine.
*
* @return None.
*
* @note None.
*
******************************************************************************/
//static void RxIntrHandler(void *Callback)
static void RxIntrHandler(XAxiDma *AxiDmaIns )
{
u32 IrqStatus;
int TimeOut;
//XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(AxiDmaIns, XAXIDMA_DEVICE_TO_DMA);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(AxiDmaIns, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
/*
* If no interrupt is asserted, we do not do anything
*/
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return;
}
/*
* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
Error = 1;
/* Reset could fail and hang
* NEED a way to handle this or do not call it??
*/
XAxiDma_Reset(AxiDmaIns);
TimeOut = RESET_TIMEOUT_COUNTER;
while (TimeOut) {
if(XAxiDma_ResetIsDone(AxiDmaIns)) {
break;
}
TimeOut -= 1;
}
return;
}
/*
* If completion interrupt is asserted, then set RxDone flag
*/
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK))
{
if(AxiDmaIns == &AxiDma)
{
DMA0RxDone = 1;
}
else if(AxiDmaIns == &AxiDma1)
{
DMA1RxDone = 1;
}
else if(AxiDmaIns == &AxiDma2)
{
DMA2RxDone = 1;
}
else if(AxiDmaIns == &AxiDma3)
{
DMA3RxDone = 1;
}
}
}
/*****************************************************************************/
/*
*
* This function setups the interrupt system so interrupts can occur for the
* DMA, it assumes INTC component exists in the hardware system.
*
* @param IntcInstancePtr is a pointer to the instance of the INTC.
* @param AxiDmaPtr is a pointer to the instance of the DMA engine
* @param TxIntrId is the TX channel Interrupt ID.
* @param RxIntrId is the RX channel Interrupt ID.
*
* @return
* - XST_SUCCESS if successful,
* - XST_FAILURE.if not succesful
*
* @note None.
*
******************************************************************************/
static void IntrHandler(void *CallBackRef, u32 Bank, u32 Status)
{
XGpioPs *Gpio = (XGpioPs *)CallBackRef;
u32 DataRead = 0;;
/* Push the switch button */
//DataRead = XGpioPs_ReadPin(Gpio, Input_Pin);
DataRead = XGpioPs_Read(Gpio, 2);
xil_printf("0x%x IntrHandler\r\n",DataRead);
if ((DataRead & 0x1) == 0x01)
{
TxIntrHandler(&AxiDma);
}
if((DataRead & 0x2) == 0x02)
{
RxIntrHandler(&AxiDma);
}
if ((DataRead & 0x4) == 0x04)
{
TxIntrHandler(&AxiDma1);
// xil_printf("data 4t\r\n");
}
if((DataRead & 0x8) == 0x08)
{
RxIntrHandler(&AxiDma1);
// xil_printf("data 4r\r\n");
}
if ((DataRead & 0x10) == 0x010)
{
TxIntrHandler(&AxiDma2);
}
if((DataRead & 0x20) == 0x20)
{
RxIntrHandler(&AxiDma2);
}
if ((DataRead & 0x40) == 0x40)
{
TxIntrHandler(&AxiDma3);
}
if((DataRead & 0x80) == 0x080)
{
RxIntrHandler(&AxiDma3);
}
else
{
}
}
/*****************************************************************************/
/**
*
* This function sets up the interrupt system for the example. It enables falling
* edge interrupts for all the pins of bank 0 in the GPIO device.
*
* @param GicInstancePtr is a pointer to the XScuGic driver Instance.
* @param GpioInstancePtr contains a pointer to the instance of the GPIO
* component which is going to be connected to the interrupt
* controller.
* @param GpioIntrId is the interrupt Id and is typically
* XPAR_<GICPS>_<GPIOPS_instance>_VEC_ID value from
* xparameters.h.
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None.
*
****************************************************************************/
int SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,
u16 GpioIntrId)
{
xil_printf("SetupInterruptSystem\r\n");
int Status;
XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */
Xil_ExceptionInit();
/*
* Initialize the interrupt controller driver so that it is ready to
* use.
*/
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
GicInstancePtr);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(GicInstancePtr, GpioIntrId,
(Xil_ExceptionHandler)XGpioPs_IntrHandler,
(void *)Gpio);
if (Status != XST_SUCCESS) {
return Status;
}
/* Enable falling edge interrupts for all the pins in bank 0. */
XGpioPs_SetIntrType(Gpio, 2, 0x00, 0xFFFFFFFF, 0x00);
/* Set the handler for gpio interrupts. */
XGpioPs_SetCallbackHandler(Gpio, (void *)Gpio, IntrHandler);
/* Enable the GPIO interrupts of Bank 2. */
XGpioPs_IntrEnable(Gpio, 2, 0xFF);
/* Enable the interrupt for the GPIO device. */
XScuGic_Enable(GicInstancePtr, GpioIntrId);
/* Enable interrupts in the Processor. */
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function disables the interrupts for DMA engine.
*
* @param IntcInstancePtr is the pointer to the INTC component instance
* @param TxIntrId is interrupt ID associated w/ DMA TX channel
* @param RxIntrId is interrupt ID associated w/ DMA RX channel
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void DisableIntrSystem(INTC * IntcInstancePtr,
u16 TxIntrId, u16 RxIntrId)
{
#ifdef XPAR_INTC_0_DEVICE_ID
/* Disconnect the interrupts for the DMA TX and RX channels */
XIntc_Disconnect(IntcInstancePtr, TxIntrId);
XIntc_Disconnect(IntcInstancePtr, RxIntrId);
#else
XScuGic_Disconnect(IntcInstancePtr, TxIntrId);
XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
#endif
}
int dma_init(void)
{
int Status;
XAxiDma_Config *Config;
XAxiDma_Config *Config1;
XAxiDma_Config *Config2;
XAxiDma_Config *Config3;
XGpioPs_Config *ConfigPtr;
u8 *RxBufferPtr = (u8 *)RX_BUFFER_BASE;
u8 *RxBufferPtr1 = (u8 *)RX_BUFFER_BASE1;
u8 *RxBufferPtr2 = (u8 *)RX_BUFFER_BASE2;
u8 *RxBufferPtr3 = (u8 *)RX_BUFFER_BASE3;
memset(RxBufferPtr,0,MAX_PKT_LEN);
memset(RxBufferPtr1,0,MAX_PKT_LEN);
memset(RxBufferPtr2,0,MAX_PKT_LEN);
memset(RxBufferPtr3,0,MAX_PKT_LEN);
xil_printf("\r\n--- Entering dma init() --- \r\n");
Config = XAxiDma_LookupConfig(0);
if (!Config) {
xil_printf("No config found for 0\r\n");
return XST_FAILURE;
}
Config1 = XAxiDma_LookupConfig(1);
if (!Config1) {
xil_printf("No config found for 1\r\n");
return XST_FAILURE;
}
Config2 = XAxiDma_LookupConfig(2);
if (!Config2) {
xil_printf("No config found for 2\r\n");
return XST_FAILURE;
}
Config3 = XAxiDma_LookupConfig(3);
if (!Config3) {
xil_printf("No config found for 3\r\n");
return XST_FAILURE;
}
/* Initialize DMA engine */
Status = XAxiDma_CfgInitialize(&AxiDma, Config);
if (Status != XST_SUCCESS) {
xil_printf("Initialization 0 failed %d\r\n", Status);
return XST_FAILURE;
}
Status = XAxiDma_CfgInitialize(&AxiDma1, Config1);
if (Status != XST_SUCCESS) {
xil_printf("Initialization 1 failed %d\r\n", Status);
return XST_FAILURE;
}
Status = XAxiDma_CfgInitialize(&AxiDma2, Config2);
if (Status != XST_SUCCESS) {
xil_printf("Initialization 2 failed %d\r\n", Status);
return XST_FAILURE;
}
Status = XAxiDma_CfgInitialize(&AxiDma3, Config3);
if (Status != XST_SUCCESS) {
xil_printf("Initialization 3 failed %d\r\n", Status);
return XST_FAILURE;
}
/* Initialize the Gpio driver. */
ConfigPtr = XGpioPs_LookupConfig(0);
if (ConfigPtr == NULL) {
return XST_FAILURE;
}
XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
/* Set the direction for the specified pin to be input */
XGpioPs_SetDirectionPin(&Gpio,54,0);
XGpioPs_SetDirectionPin(&Gpio,55,0);
XGpioPs_SetDirectionPin(&Gpio,56,0);
XGpioPs_SetDirectionPin(&Gpio,57,0);
XGpioPs_SetDirectionPin(&Gpio,58,0);
XGpioPs_SetDirectionPin(&Gpio,59,0);
XGpioPs_SetDirectionPin(&Gpio,60,0);
XGpioPs_SetDirectionPin(&Gpio,61,0);
/*
* Setup the interrupts such that interrupt processing can occur. If
* an error occurs then exit.
*/
Status = SetupInterruptSystem(&Intc, &Gpio, XPAR_XGPIOPS_0_INTR);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrDisable(&AxiDma1, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable(&AxiDma1, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrEnable(&AxiDma1, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(&AxiDma1, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrDisable(&AxiDma2, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable(&AxiDma2, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrEnable(&AxiDma2, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(&AxiDma2, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrDisable(&AxiDma3, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable(&AxiDma3, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrEnable(&AxiDma3, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(&AxiDma3, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
/**************************************************************************/
// Status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR,0x58);
// xil_printf(" RX length is 0x%x\r\n",Status);
// Status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR,0x28);
// xil_printf("TX length is 0x%x\r\n",Status);
/**************************************************************************/
Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) RxBufferPtr,
MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = XAxiDma_SimpleTransfer(&AxiDma1,(UINTPTR) RxBufferPtr1,
MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = XAxiDma_SimpleTransfer(&AxiDma2,(UINTPTR) RxBufferPtr2,
MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = XAxiDma_SimpleTransfer(&AxiDma3,(UINTPTR) RxBufferPtr3,
MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/* Initialize flags before start transfer test */
TxDone = 0;
DMA0RxDone = 0;
DMA1RxDone = 0;
DMA2RxDone = 0;
DMA3RxDone = 0;
Error = 0;
}
int dma_8_10b_send(XAxiDma* AxiDmaIns,u8 *wBuffer , unsigned int length)
{
int Status;
u8 *TxBufferPtr;
if((AxiDmaIns == NULL)||(wBuffer == NULL))
{
xil_printf("send Pointer err\r\n");
return XST_FAILURE;
}
if (AxiDmaIns == &AxiDma)
TxBufferPtr = (u8 *)TX_BUFFER_BASE ;
else if(AxiDmaIns == &AxiDma1)
TxBufferPtr = (u8 *)TX_BUFFER_BASE1 ;
else if(AxiDmaIns == &AxiDma2)
TxBufferPtr = (u8 *)TX_BUFFER_BASE2 ;
else if(AxiDmaIns == &AxiDma3)
TxBufferPtr = (u8 *)TX_BUFFER_BASE3 ;
else
{
xil_printf("para err\r\n");
return XST_FAILURE;
}
memset(TxBufferPtr,0,length);
memcpy(TxBufferPtr,wBuffer,length);
Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN);
Status = XAxiDma_SimpleTransfer(AxiDmaIns,(UINTPTR) TxBufferPtr,
length, XAXIDMA_DMA_TO_DEVICE);
// xil_printf("status is %d",Status);
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}
return XST_SUCCESS;
}
unsigned int dma_8_10b_recv(XAxiDma* AxiDmaIns,u8 *rBuffer)
{
int Status;
int i;
int Length = 0 ;
u8 *RxBufferPtr;
Length = XAxiDma_ReadReg(AxiDmaIns->RegBase,0x58);
if((AxiDmaIns == NULL)||(rBuffer == NULL))
{
xil_printf("recv Pointer err\r\n");
return XST_FAILURE;
}
if (AxiDmaIns == &AxiDma)
RxBufferPtr = (u8 *)RX_BUFFER_BASE ;
else if(AxiDmaIns == &AxiDma1)
RxBufferPtr = (u8 *)RX_BUFFER_BASE1 ;
else if(AxiDmaIns == &AxiDma2)
RxBufferPtr = (u8 *)RX_BUFFER_BASE2 ;
else if(AxiDmaIns == &AxiDma3)
RxBufferPtr = (u8 *)RX_BUFFER_BASE3 ;
else
{
xil_printf("para err\r\n");
return XST_FAILURE;
}
Xil_DCacheInvalidateRange(RxBufferPtr,MAX_PKT_LEN);
for(i = 0; i < Length; i++)
{
rBuffer[i] = RxBufferPtr[i];
}
Status = XAxiDma_SimpleTransfer(AxiDmaIns,(UINTPTR) RxBufferPtr,
MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return Length;
}Demo部分如下void Xdma_demo()
{
int Status;
int Length;
u8 rBuffer[256] = {0};
u8 wBuffer[256] = {0};
int i;
dma_init();
for(i=0;i<256;i++)
{
wBuffer[i]=i+1;
}
dma_8_10b_send(&AxiDma,wBuffer,4);
for(i=0;i<256;i++)
{
wBuffer[i]=i+2;
}
dma_8_10b_send(&AxiDma1,wBuffer , 16);
for(i=0;i<256;i++)
{
wBuffer[i]=i+3;
}
dma_8_10b_send(&AxiDma2,wBuffer , 32);
for(i=0;i<256;i++)
{
wBuffer[i]=i+4;
}
dma_8_10b_send(&AxiDma3,wBuffer , 32);
while(1)
{
if(DMA0RxDone == 1)
{
// Status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR,0x58);
// xil_printf("length2 is 0x%x\r\n",Status);
// Status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR,0x28);
// xil_printf("TX length2 is 0x%x\r\n",Status);
Length = dma_8_10b_recv(&AxiDma,rBuffer);
xil_printf("length DMA0 is 0x%x\r\n",Length);
xil_printf("DATE: ");
for(i=0; i<33; i++)
{
xil_printf("%x ",rBuffer[i]);
}
xil_printf("\r\n");
DMA0RxDone = 0;
}
if(DMA1RxDone == 1)
{
Length = dma_8_10b_recv(&AxiDma1,rBuffer);
xil_printf("length DMA1 is 0x%x\r\n",Length);
xil_printf("DATE: ");
for(i=0; i<33; i++)
{
xil_printf("%x ",rBuffer[i]);
}
xil_printf("\r\n");
DMA1RxDone = 0;
}
if(DMA2RxDone == 1)
{
dma_8_10b_recv(&AxiDma2,rBuffer);
xil_printf("DATE: ");
for(i=0; i<33; i++)
{
xil_printf("%x ",rBuffer[i]);
}
xil_printf("\r\n");
DMA2RxDone = 0;
}
if(DMA3RxDone == 1)
{
dma_8_10b_recv(&AxiDma3,rBuffer);
xil_printf("DATE: ");
for(i=0; i<33; i++)
{
xil_printf("%x ",rBuffer[i]);
}
xil_printf("\r\n");
DMA3RxDone = 0;
}
}
} dma_8_10b_send()为封装后的发送函数,将宏定义的四路TXBUFFER和DMA匹配,实现DMA向设备发送数据的功能,并通过Xil_DCacheFlushRange()函数清理缓存 dma_8_10b_recv()为封装后的接收函数,将宏定义的四路RXBUFFER和DMA匹配,实现DMA接收设备发送的数据的功能,数据长度通过读取DMA长度寄存器获得,这样的话更具有普遍性,同样通过Xil_DCacheFlushRange()函数清理缓存 XAxiDma_SimpleTransfer是其原型,最后一个参数表示了传输方向收发的处理函数基本上是AXIDMA例程里的,仅对多余的接收完成标志位做了补充(多余的应该没了,也能在导入一个工程比较一下)哦对了很奇怪的一点是初始化的时候需要提前做一次接受的transfer,还没发现原因,在之后的挂载操作系统时也有一次类似的操作,当然linux下的transfer不是官方提供的,可能和裸板有些许差异,而且不提前做也没法从0x58的长度寄存器读取实际搬移数据的长度,另说了 初始化部分是结合了之前章节讲的GPIO中断,没有用例程中的中断方式先写这么多了,目前只了解到这些,SG模式的用法后续有机会更新吧参考:芯片手册 原子开发手册 CSDN Xilinx社区等网络资源