文章目录
一 准备开发环境
1.硬件
PC:win10 64位
开发板:TL6678-EVM
仿真器:TL-XDS200
网线*1
2.软件
DSP集成开发环境:CCSv5.5 ,Sys/Bios平台,NDK组件,C语言
上位机开发环境:vs2019 ,C#语言
辅助工具:DHCPsrvV1.7、Beyond Compare 4
二 图像数据处理与传输框架
1. 上位机通过PC网口发送一张BMP图片
1)vs2019建立C#工程。
1.1)控件介绍
From.cs窗口布局拉出8个控件。如图1.1。TextBox1显示所选图片的路径,“选择”按钮触发文件对话框,选择一张要发送的BMP图片。TestBox2提供给用户输入DSP服务器的IP地址,TextBox3提供给用户输入端口号。TestBox2、TextBox3会直接显示我在代码里写好的IP地址和端口号值,不用我每次连接都输入一遍。“发送”按钮触发建立Socket通信,连接服务器。TextBox4区域显示用户提示信息。Label区域显示PC接收DSP回发数据后保存为BMP图时生成的绝对路径。PictureBox显示新生成的BMP图片,其控件属性SizeMode已经设置为图片显示自适应控件大小。
2)代码简析
打开文件选择对话框
/// <summary>
/// 选择文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void butChoose_Click(object sender, EventArgs e)
{
//打开文件
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "请选择要传的文件";
ofd.InitialDirectory = @"C:\Users\Administrator\Desktop";
ofd.Filter = "所有文件|*.*|文本文件|*.txt|表格文件|*.xlsx|视频文件|*.avi";
ofd.ShowDialog();
//得到选择文件的路径
textFile.Text = ofd.FileName;
}
设定服务器的IP地址及端口号
private void Form1_Load(object sender, EventArgs e)
{
//不检测跨线程之间的空间调用
Control.CheckForIllegalCrossThreadCalls = false;
textIP.Text = "192.168.0.186";
textPort.Text = "1025";
}
创建Socket通信,连接DSP服务器
private void butConnect_Click(object sender, EventArgs e) //点击了发送按钮就进入了这个成员函数
{
try
{
//创建负责通信的socket
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获取服务端的IP
IPAddress ip = IPAddress.Parse(textIP.Text.Trim());
//获取服务端的端口号
IPEndPoint port = new IPEndPoint(ip, Convert.ToInt32(textPort.Text));
//获得要连接的远程服务器应用程序的IP地址和端口号
socketSend.Connect(port);
ShowMsg("连接成功,正在发送.......");
文件操作,读取并发送BMP图片数据
using (FileStream fsread = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read))
{
byte[] buffer_header = new byte[54]; //声明一个54个字节大小的数组
byte[] buffer = new byte[1024 * 1024 * 8]; //声明一个8KB字节大小的数组
fsread.Read(buffer_header, 0, 54); //读取54个字节的内容到buffer_header数组
socketSend.Send(buffer_header, 0, 54, SocketFlags.None);//往DSP发送54个字节
while (true)
{
int r2 = fsread.Read(buffer, 0, buffer.Length);
file_lenth += r2;
if (r2 == 0)
{
file_lenth += 54;
ShowMsg("发送完成/累计发送字节:" + file_lenth.ToString());
file_lenth1 = file_lenth;
file_lenth = 0;
break;
}
socketSend.Send(buffer,0, r2, SocketFlags.None);
}
}
2. DSP通过ETH0接收图片完整数据
1)建立DSP工程
在CCSv5.5的集成开发环境中,导入广州创龙提供的TL6678-EVM评估板SYS/BIOS系统例程,打开NDK_TCP例程,接下来所有的代码修改基本都在TCP.c这个文件里。
2)修改内存配置
打开这个工程下的app.cfg文件,打开后点击下方的cfg Script这一项,再定位到“内存配置”这一栏,修改原先创龙公司分配的堆空间大小,具体修改大小自行斟酌,我这里修改为250MB。原本分配的堆空间大小只有1MB,如若不修改,当你使用堆内存存储PC传输的大文件时,必定报错,大概意思就是heap error,这也是我遇到并修复的问题之一。
3)配置DSP使用ETH0和动态获取IP地址
在创龙提供的用户例程开发手册里已经提供了网络配置的方法,百度一下也有了,基本上都差不多,都是基于TI的官方例程来修改的。创龙默认是配置为使用ETH1和静态IP地址的,所以我要重新配置,完了之后没有获取到IP地址的,最后我找到了一个可以辅助我们的CCS自动获取IP地址的工具DHCPsrvV1.7,这个工具非常好用,我也会放到资源上,大家需要的话可以下载。
FHCPsrvV1.7资源下载地址;
https://download.csdn.net/download/weixin_42696672/12272936
4)代码简析
先接收BMP图像的前54个字节,并根据公式解析出图像的像素大小
int nr,total=0; //nr:保存返回值 ;total:协助计算接收的字节数
unsigned char *pBuf54; //存放位图文件头的变量
pBuf54 = (unsigned char*)malloc(54); //动态分配给pBuf54变量54个字节的空间
nr=(int)recvnc( s, (void**)&pBuf54, 0, &hBuffer ); //接收PC端发送过来的信息,存放在pBuf54
int W1,H1; //保存图像的宽度、高度的变量
W1 = (int)(pBuf54[18])+(int)(pBuf54[19]) * 256 +(int)(pBuf54[20]) * 256 * 256 + (int)(pBuf54[21]) * 256 * 256 * 256; //计算图像宽度的公式,根据位图信息头里面保存的数据可知,第18个~21个字节
H1 = (int)(pBuf54[22])+(int)(pBuf54[23]) * 256 +(int)(pBuf54[24]) * 256 * 256 + (int)(pBuf54[25]) * 256 * 256 * 256; //计算图像高度的公式,根据位图信息头里面保存的数据可知,第22~25个字节
printf("W1 = %d,H1 = %d,W1*H1*3 = %d Bytes\n",W1,H1,W1*H1*3);
完整接收PC发来的图像数据,首先开辟出一个图片大小的堆空间以存储数据,接着不断接收数据包,并且通过改变指针下标存储到堆内存。
unsigned char *imagedatatuGUODU; //存放PC端发送过来的图像本身的数据变量,PC段会从图像的最后一个数据开始往DSP端发
imagedatatuGUODU = (unsigned char*)malloc(W1 * H1 * 3); //根据前面计算出来的图像宽度和高度,动态分配内存空间的大小
if( imagedatatuGUODU == NULL )
{
printf("imagedatatuGUODU malloc failed!!!\n");
exit(1);
}
else
{
printf("imagedatatuGUODU malloc successed!!!\n"); //成功分配了空间
}
nr = 0; //这里也是协助存放空间的地址往后偏移
//这段是接收PC端发来的图像本身的数据
while(1)
{
nr = recv(s,(unsigned char*)(imagedatatuGUODU+total),unit,0);
if (nr > 0)
{
total += nr;
if (total == W1*H1*3)
{
printf("DSP recv complete!!! Integrated reception %d bytes\n ",total);
break; //当累计接收到的数据==图像本身数据大小时,表明接收完整,可以退出这个循环。
}
}
else
{
printf( "peer close the socket.recv fail!!!" ); //对端关闭了连接
break; //真的出错了
}
}
3. DSP对图片数据进行处理(略)
这部分处理我没有做,有能力者请自行在DSP代码里添加一段图像处理的功能函数,如对像素值取补,处理后为灰度图,或者是旋转、缩放等等,最后要在回发数据前被调用就可以了。这里我也给大家一个参考的链接,是别人写的博客。
参考博客
https://blog.csdn.net/fengyhack/article/details/43529379
4. DSP回发数据给PC
将前面存储的数据全部回发给PC端,第一次要先发前54个字节,后面就是不断发数据包。其实PC端和DSP端的收发代码思路是一样的。
//以下往PC回发数据
send(s,pBuf54,54,0);
int III;
int end = W1 * H1 * 3;
int data_total = end;
int send_zijie_total = 0; //协助实现地址偏移
int send_zijie_ret = 0; //记录发送出去的字节数
//发送图像本身的数据,直到发送完成则跳出循环
while(1)
{
if (end >= unit)
{
III = unit; //剩余很多信息,所以下次继续取unit个字节来发送
}
else
{
III = end; //剩下的已经不足一块unit字节,就读剩下的字节数
}
send_zijie_ret= send(s, (unsigned char *)(imagedatatuGUODU+send_zijie_total),III,0);
send_zijie_total += send_zijie_ret;
//当发送的字节数和图像本身的总字节数相等时,表明发送完成,可以退出循环
if ( send_zijie_total == data_total )
{
printf("The image transmission completion !!! accumulated transmission %d bytes\n",send_zijie_total);
break;
}
if(send_zijie_ret == SOCKET_ERROR)
{
printf("send() failed!\n");
break;
}
end -= unit; //每发送一次减一次
}
5. 上位机接收数据并另存为BMP图片
5.1)获取当前系统时间,转换为字符串,作为生成的bmp图片名。
//保存接收的文件
string filePath = "";
filePath = @"F:\Data\";
string createPath = filePath + '\\' + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".bmp";
5.2)打开生成的BMP图,进行文件操作,写入接收到的数据。
using (FileStream fsWrite = new FileStream(createPath, FileMode.OpenOrCreate, FileAccess.Write))
{
long recive_length = 0; //接收大文件总的字节数
byte[] recv_header = new byte[54];
byte[] buffer = new byte[1024 * 1024 * 8];
socketSend.Receive(recv_header); //先接收54个字节数
fsWrite.Write(recv_header, 0, 54); //将接收到的数据都写入保存的图片里
while (true)
{
int r1 = socketSend.Receive(buffer); //实际接收的有效字节数
recive_length += r1;
if( r1 > 0 )
fsWrite.Write(buffer, 0, r1); //将接收到的数据都写入保存的图片里
2)当已经接收到的数据的累计大小和原文件大小一样时,说明文件接受完成,就可以关闭当前文件流,并跳出循环了。还可以将当前接收的图片加载显示到控件pictureBox
if (recive_length == (file_lenth1 - 54) )
{
recive_length += 54;
ShowMsg("接收完成/累计接收字节:" + recive_length.ToString());
file_lenth1 = 0;
// ShowMsg("保存路径:" + createPath);
fsWrite.Close();
fsWrite.Dispose();
saveName.Text = createPath ;
if (createPath != string.Empty)
{
try
{
this.pictureBox.Load(createPath); //显示图片
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
break;
}
三 测试效果
肉眼有时候无法分辨出两张图片有无区别,我们可以通过其他软件对原图和接收的图片进行二进制格式转换,再对比,看两张图片是否完全一样。我使用Beyond Compare 4这个软件,它有30天的免费使用。
打开后,点击右侧箭头切换到下一页,选择图片比较。
分别打开两张图片,自动会对比,结果很快就会出现,左下方显示“二进制相同”说明两张图片是完全一样的。
Beyond Compare 4资源下载地址
由于上传的资源审核不通过,理由是违规,所以我放到下面我的工程里的文件夹里,需要的可以下载。
附录
完整DSP工程和上位机工程资源及Beyond Compare 4下载地址:
https://download.csdn.net/download/weixin_42696672/12275460