You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

339 lines
11 KiB
C

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/timeb.h>
// 函数:从设备读取数据到本地内存(缓冲区)
// 功能:实现设备到主机的数据传输
// 参数:
// dev_fd : 设备实例句柄
// addr : 设备中的源地址
// buffer : 缓冲区基指针
// size : 数据大小
// 返回值:
// 成功0失败-1
int dev_read (int dev_fd, uint64_t addr, void *buffer, uint64_t size) {
if ( addr != lseek(dev_fd, addr, SEEK_SET) ) // 调整文件偏移到指定地址
return -1; // 偏移失败
if ( size != read(dev_fd, buffer, size) ) // 从设备读取数据到缓冲区
return -1; // 读取失败
return 0;
}
// 函数:从本地内存(缓冲区)写数据到设备
// 功能:实现主机到设备的数据传输
// 参数:
// dev_fd : 设备实例句柄
// addr : 设备中的目标地址
// buffer : 缓冲区基指针
// size : 数据大小
// 返回值:
// 成功0失败-1
int dev_write (int dev_fd, uint64_t addr, void *buffer, uint64_t size) {
if ( addr != lseek(dev_fd, addr, SEEK_SET) )
return -1;
if ( size != write(dev_fd, buffer, size) )
return -1;
return 0;
}
// 函数:获取毫秒级别的时间
// 功能:返回当前时间的毫秒数
static uint64_t get_millisecond () {
struct timeb tb;
ftime(&tb);
return (uint64_t)tb.millitm + (uint64_t)tb.time * 1000UL;
// tb.time is the number of seconds since 00:00:00 January 1, 1970 UTC time;
// tb.millitm is the number of milliseconds in a second
}
// 函数:解析无符号整数
// 功能从字符串中解析出十六进制或十进制的无符号64位整数
// 参数:
// string : 输入的字符串
// pvalue : 解析后的值的指针
// 返回值:
// 成功解析的项数失败则为0
int parse_uint (char *string, uint64_t *pvalue) {
if ( string[0] == '0' && string[1] == 'x' ) // 十六进制格式"0xXXXXXXXX"
return sscanf( &(string[2]), "%lx", pvalue);
else // 十进制格式
return sscanf( string , "%lu", pvalue);
}
#define DMA_MAX_SIZE 0x10000000UL // DMA操作的最大尺寸定义 256kb
char USAGE[] =
"Usage: \n"
"\n"
" 写入设备(主机到设备):\n"
" %s <文件名> to <设备名> <设备内地址> <大小>\n"
" 示例:\n"
" %s data.bin to /dev/xdma0_h2c_0 0x100000 0x10000\n"
"\n"
" 读取设备(设备到主机):\n"
" %s <文件名> from <设备名> <设备内地址> <大小>\n"
" 示例:\n"
" %s data.bin from /dev/xdma0_c2h_0 0x100000 0x10000\n";
int main (int argc, char *argv[]) {
int ret = -1;
uint64_t millisecond;
char usage_string [1024];
char *dev_name, *file_name;
char direction;
uint64_t address, size;
int dev_fd = -1;
FILE *file_p = NULL;
void *buffer = NULL;
sprintf(usage_string, USAGE, argv[0], argv[0], argv[0], argv[0] );
if (argc < 6) { // not enough argument
puts(usage_string);
return -1;
}
file_name = argv[1];
direction = argv[2][0];
dev_name = argv[3];
if ( 0 == parse_uint(argv[4], &address) ) { // parse the address in the device
puts(usage_string);
return -1;
}
if ( 0 == parse_uint(argv[5], &size ) ) { // parse the size in the device
puts(usage_string);
return -1;
}
// print information:
if (direction == 't') { // to (write device, host-to-device)
printf("from : %s\n" , file_name);
printf("to : %s addr=0x%lx\n" , dev_name, address);
printf("size : 0x%lx\n\n" , size);
} else if (direction == 'f') { // from (read device, device-to-host)
printf("from : %s addr=0x%lx\n" , dev_name, address);
printf("to : %s\n" , file_name);
printf("size : 0x%lx\n\n" , size);
} else {
puts(usage_string);
return -1;
}
if (size > DMA_MAX_SIZE || size == 0) {
printf("*** ERROR: DMA size must larger than 0 and NOT be larger than %lu\n", DMA_MAX_SIZE);
return -1;
}
buffer = malloc(size); // allocate local memory (buffer)
if (buffer == NULL) {
printf("*** ERROR: failed to allocate buffer\n");
goto close_and_clear;
}
dev_fd = open(dev_name, O_RDWR); // open device
if (dev_fd < 0) {
printf("*** ERROR: failed to open device %s\n", dev_name);
goto close_and_clear;
}
file_p = fopen(file_name, direction == 't' ? "rb" : "wb"); // open file for read/write
if (file_p == NULL) {
printf("*** ERROR: failed to open file %s\n", file_name);
goto close_and_clear;
}
millisecond = get_millisecond(); // start time
if (direction == 't') {
if ( size != fread(buffer, 1, size, file_p) ) { // local file -> local buffer
printf("*** ERROR: failed to read %s\n", file_name);
goto close_and_clear;
}
if ( dev_write(dev_fd, address, buffer, size) ) { // local buffer -> device
printf("*** ERROR: failed to write %s\n", dev_name);
goto close_and_clear;
}
} else {
if ( dev_read(dev_fd, address, buffer, size) ) { // device -> local buffer
printf("*** ERROR: failed to read %s\n", dev_name);
goto close_and_clear;
}
if ( size != fwrite(buffer, 1, size, file_p) ) { // local buffer -> local file
printf("*** ERROR: failed to write %s\n", file_name);
goto close_and_clear;
}
}
millisecond = get_millisecond() - millisecond; // get time consumption
millisecond = (millisecond > 0) ? millisecond : 1; // avoid divide-by-zero
printf("time=%lu ms data rate=%.1lf KBps\n", millisecond, (double)size / millisecond );
ret = 0;
close_and_clear:
if (buffer != NULL)
free(buffer);
if (dev_fd >= 0)
close(dev_fd);
if (file_p != NULL)
fclose(file_p);
return ret;
}
int main(int argc, char *argv[]) {
int ret = -1; // 初始化返回值为-1表示程序可能运行失败
uint64_t millisecond; // 用于存储操作所花费的毫秒数
char usage_string[1024]; // 存储程序使用说明的字符串
char *dev_name, *file_name; // 分别指向设备名和文件名的指针
char direction; // 存储传输方向的字符,'t' 表示写入设备,'f' 表示读取设备
uint64_t address, size; // 存储设备地址和传输数据大小
int dev_fd = -1; // 设备文件描述符,初始设置为-1表示未打开设备
FILE *file_p = NULL; // 文件指针初始为NULL
void *buffer = NULL; // 数据缓冲区指针初始为NULL
// 根据程序名和命令行参数构造使用说明字符串
sprintf(usage_string, USAGE, argv[0], argv[0], argv[0], argv[0]);
// 检查命令行参数数量是否足够
if (argc < 6) {
puts(usage_string); // 打印使用说明
return -1; // 参数不足,退出程序
}
// 解析命令行参数
file_name = argv[1];
direction = argv[2][0];
dev_name = argv[3];
// 解析设备地址和数据大小,如果解析失败则打印使用说明并退出
if (parse_uint(argv[4], &address) == 0) {
puts(usage_string);
return -1;
}
if (parse_uint(argv[5], &size) == 0) {
puts(usage_string);
return -1;
}
// 根据传输方向打印操作信息
if (direction == 't') {
printf("从: %s\n至: %s 地址=0x%lx\n大小: 0x%lx\n", file_name, dev_name, address, size);
} else if (direction == 'f') {
printf("从: %s 地址=0x%lx\n至: %s\n大小: 0x%lx\n", dev_name, address, file_name, size);
} else {
puts(usage_string);
return -1; // 无效的方向参数
}
// 检查数据大小是否合法
if (size > DMA_MAX_SIZE || size == 0) {
printf("*** 错误: DMA大小必须大于0且不超过 %lu\n", DMA_MAX_SIZE);
return -1;
}
// 分配缓冲区
buffer = malloc(size);
if (buffer == NULL) {
printf("*** 错误: 分配缓冲区失败\n");
goto close_and_clear; // 跳转到资源释放部分
}
// 打开设备
dev_fd = open(dev_name, O_RDWR);
if (dev_fd < 0) {
printf("*** 错误: 打开设备 %s 失败\n", dev_name);
goto close_and_clear;
}
// 打开文件
file_p = (direction == 't') ? fopen(file_name, "rb") : fopen(file_name, "wb");
if (file_p == NULL) {
printf("*** 错误: 打开文件 %s 失败\n", file_name);
goto close_and_clear;
}
// 记录操作开始时间
millisecond = get_millisecond();
// 根据传输方向进行读写操作
if (direction == 't') { // 写入设备
if (fread(buffer, 1, size, file_p) != size) {
printf("*** 错误: 读取文件 %s 失败\n", file_name);
goto close_and_clear;
}
if (dev_write(dev_fd, address, buffer, size)) {
printf("*** 错误: 写入设备 %s 失败\n", dev_name);
goto close_and_clear;
}
} else { // 读取设备
if (dev_read(dev_fd, address, buffer, size)) {
printf("*** 错误: 读取设备 %s 失败\n", dev_name);
goto close_and_clear;
}
if (fwrite(buffer, 1, size, file_p) != size) {
printf("*** 错误: 写入文件 %s 失败\n", file_name);
goto close_and_clear;
}
}
// 计算并打印操作耗时和数据传输速率
millisecond = get_millisecond() - millisecond;
millisecond = (millisecond > 0) ? millisecond : 1; // 避免除以零错误
printf("耗时=%lu 毫秒 数据速率=%.1lf KB/s\n", millisecond, (double)size / millisecond / 1024);
ret = 0; // 如果一切正常设置返回值为0表示成功
close_and_clear: // 清理资源标签
// 释放缓冲区
if (buffer != NULL)
free(buffer);
// 关闭设备文件
if (dev_fd >= 0)
close(dev_fd);
// 关闭文件
if (file_p != NULL)
fclose(file_p);
return ret; // 返回程序执行结果
}