mobile CCTV,mobile surveillance,police body worn cameras
标题: 使用CUSDK做二次开发 串口透传数据的功能说明 [打印本页]
author: besovideo time: 2018-3-29 12:20
标题: 使用CUSDK做二次开发 串口透传数据的功能说明
使用CUSDK做二次开发串口透传数据的功能说明CUSDK在网盘SDK目录下可下载:
我们所有的软件,目前都通过QQ网盘提供下载:
(包含PC端接收浏览视频的客户端软件:smarteye client以及流媒体服务器smarteye server,SDK,手机拍传软件APP-MPU,手机客户端软件APP-MCU,局域网搜索配置工具、产品手册、文档、固件)
这个网盘链接永久有效,请保留收藏。
1.工程的切入点:1.先分析MFCDemo工程中打开串口/gps的方案,再结合WinFormDemo的实际情况处理。
2.透明串口和gps功能很接近,可以仿照,从WinFormDemo中Dialog.cs打开gps切入。
2.具体分析:概述:整个 OnNMDblclkChannelList 过程需要获取 PU 列表,打开 GPS_TSP 通道(打开通道的时候要对数据进行设定解码);除此以外,其他过程还要负责 GPS 信息框内显示。
如何获取 PU 列表?TSP 通道并不是由服务器泵上去的,因此我们通过人工添加“假通道”来实现服务器泵上去的功能,让他出现在每个 PU列表中的最后方,也就是每当 gps 通道添加完成之后,手动添加 tsp 通道,代码位于 MDataList.cpp 中的 CMDataList::InsertPu:
/* 假 通道, 用于测试 串口 */
strcpy(onePu->pChannel.szName,"TSP");
onePu->pChannel.iChannelIndex= BVCU_SUBDEV_INDEXMAJOR_MIN_TSP;
onePu->pChannel.iMediaDir =BVCU_MEDIADIR_DATARECV;
onePu->iChannelCount ++;
/* 假通道 */
注:InsertPu 具体由谁调用,以及如何改动不作具体分析,这不是本文档探讨的重点。
打开GPS_TSP 通道的实现。在 MFCDemoDlg.cpp 中,我们通过 OpenGPS_TSP 打开 GPS/TSP 通道,OpenGPS_TSP 定义于 MLibBVCU.cpp 中,具体定义形式为CMLibBVCU::OpenGPS_TSP,这个函数需要处理四个数据(实际上就是参数的设置),由于 m_session 已经被定义为类 CMLibBVCU 的静态成员,因此只需传递三个参数。GPS/TSP 的区别在于解码的不同;此外显示GPS/TSP 通道里面数据的方法也不一样,这个不是重点,但是在后面的 C# 工程中体现了这一点,因此提一下。
/* 略过部分请看具体工程源码,以后不再赘述 */
int CMLibBVCU::OpenGPS_TSP(BVCU_HDialog* phDialog,constchar* puId,intchannel)
{
……
/* 参数的设置略过,串口和 gps 很接近,因此可以共用一套方法,区别之一是解码的不同 */
if(BVCU_SUBDEV_INDEXMAJOR_MIN_GPS <= channel && channel <=BVCU_SUBDEV_INDEXMAJOR_MAX_GPS)
dlgParam.afterDecode =afterDecode_GPS;
else
dlgParam.afterDecode =afterDecode_TSP;
/* 以下省略的部分不重要,用于设置其他参数的,略过 */
……
returnBVCU_Dialog_Open(phDialog,&dlgParam,&dlgCtrlParam);
}
return BVCU_RESULT_E_FAILED;
}
/* 这是具体的解码过程,用到了 m_OnRecvTSPData*/
BVCU_ResultCMLibBVCU::afterDecode_TSP(BVCU_HDialog hDialog, SAVCodec_Context* pCodec,SAV_Frame* pFrame)
{
if (hDialog && pFrame)
{
if(pFrame->ppData[0])
{
if(m_OnRecvTSPData)
m_OnRecvTSPData(hDialog, (char*)pFrame->ppData[0], pFrame->iDataSize[0]);
}
}
return BVCU_RESULT_S_OK;
}
注:具体改动请比较该工程和以前 MLibBVCU.* 区别,“*” 包含“.h”“.cpp”,显示部分不再分析,不是重点略过,至此 MFCDemo 工程的重点分析完毕。
现在我们看 WinFormDemo 工程!
概述:C# 工程因为不能直接调用 C++ 工程代码,因此必须把C++ 工程封装为 dll 调用,而提供 ManagedLayer.dll 的封装层是 ManagedLayer 这个 C++ 工程。在 MFCDemo 中,我们可以共用方法 OpenGPS_TSP 源于两个前提,1.MFCDemo 是 C++ 工程,可以直接调用位于 include 文件中的底层函数BVCU_dialog_open 2.MFCDemo 是C++ 工程,很多参数可以方便的共享和传入,所以共用方法OpenGPS_TSP 只需传递三个参数(实际设置了四个参数,额外的参数是 m_session),显示 TSP 和 GPS 信息的函数可以共享,也可以单独设立,只需直接调用即可。对比 C# 工程会发现,1.C# 工程无法调用位于 include 文件中的底层函数 BVCU_dialog_open,除非他调用 ManagedLayer 提供的接口,从而间接的调用它 2.C# 工程无法与 C++ 工程直接共享和传递参数,因此打开 GPS 的函数必须由 BVCU.cs 中的 DllImport 载入,并且传递完整的 7 个参数,如同该例子:
[DllImport("ManagedLayer.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int ManagedLayer_CuOpenGpsDialog(IntPtr handle, refIntPtr dialog, IntPtrsession, Byte[] puId, int channelNo,
EventHandler.BVCU_GpsDialog_OnEvent onDlgEvent, EventHandler.BVCU_GpsDialog_OnDataonDlgData);
[DllImport("ManagedLayer.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int ManagedLayer_CuOpenTspDialog(IntPtr handle, refIntPtr dialog, IntPtrsession, Byte[] puId, int channelNo,
EventHandler.BVCU_TspDialog_OnEvent onDlgEvent, EventHandler.BVCU_TspDialog_OnDataonDlgData);
起初,我也尝试了一个上午的时间,试图通过修改 C# 的委托函数 EventHandler.BVCU_GpsDialog_OnEvent , EventHandler.BVCU_GpsDialog_OnData 和 ManagedLayer 工程中的相关函数以达到 GPS 兼容 TSP 的打开,使得 GPS/TSP 共用一套方法。然而,因为 GPS 解码委托的传入参数和TSP 解码委托传入参数有本质的不同,最终宣告失败。
切入思路如法炮制:“假通道”的添加,分别打开 GPS 或 TSP,分别显示 GPS 或 TSP,但是在显示上我们共用GPS 的显示框,所以 TSP 输出内容为:经度框里面显示的实际是接收的字符串,纬度框里面显示的实际是该字符串的长度。
2.1添加“假通道” 概述:完成一些列初始化登陆之后,EventHandle 会被触发从而使用委托的方式,完成一系列的动作。对于委托,可以这样理解(见下面的标注):
EventHandle.cs 的代码,以下均是:
public EventHandler()
{
//dialog_OnDialogEvent,我 EventHandle 把下述职责委托于你,使得你负责处理 BVCU_Dialog_OnDialogEvent的所有事件,处理好了向某个人交代。某个人指的是,真正需要处理该事件的方法,处理好了只有在运行时才能决定。
……略过原有代码
//该处是我添加的用于处理串口事件、接收数据的两个委托
BVCU_TspDialog_OnEvent(TspDialog_OnEvent);
tspDialog_OnData = new BVCU_TspDialog_OnData(TspDialog_OnData);
……略过原有代码
//该处是原有代码,但是在委托给 Cmd_OnGetPuList之后,被委托方使用 Cmd_OnGetPuList(注意区分大小写)的过程中是我修改的代码,添加了“假通道”
cmd_OnGetPuList = new BVCU_Cmd_OnGetPuList(Cmd_OnGetPuList);
……略过原有代码
}
Cmd_OnGetPuList 如何添加“假通道”的(因为我只判断了小写的“gps”,所以 PU 列表中只有包含小写的“gps”通道才会被添加“TSP”通道):
/*
* Get Pu List
*/
public BVCU_Cmd_OnGetPuList cmd_OnGetPuList;
voidCmd_OnGetPuList(IntPtr session, IntPtr ptPuId, IntPtrptPuName, int iStatus, refBVCU_PUOneChannelInfo channel, int iFinished)
{
stringpuId = Marshal.PtrToStringAnsi(ptPuId, BVCU.BVCU_MAX_ID_LEN + 1).Split('\0')[0];
stringpuName = Marshal.PtrToStringAnsi(ptPuName, BVCU.BVCU_MAX_NAME_LEN + 1).Split('\0')[0];
if(BVCU.TRUE(iFinished))
{
m_session.OnGetPuListFinished();
}
Session.Channel chnl = newSession.Channel();
if(iStatus == BVCU.BVCU_ONLINE_STATUS_OFFLINE)
{
chnl.online = false;
}
else
{
chnl.online = true;
}
getChannel(chnl, channel);
m_session.OnGetPu(puName, puId,chnl);
if(channel.szName.Equals("gps"))
{
// 假通道,用于串口测试,这里我只判断了小写的 gps,因为 PU_2740 底下的 gps 是小写的,我所要测试的透明串口就是 PU_2740,如果有变更需要,只需手动修改 if 条件即可
chnl = newSession.Channel();
channel.szName = "TSP";
channel.iPTZIndex = 15;
channel.iMediaDir = 32;
channel.iChannelIndex = 65792;
if(iStatus == BVCU.BVCU_ONLINE_STATUS_OFFLINE)
{
chnl.online = false;
}
else
{
chnl.online = true;
}
getChannel(chnl, channel);
m_session.OnGetPu(puName, puId,chnl);
}
}
2.2分别打开 GPS 或TSP该代码位于Form1.cs中,其中 m_sdkOperator.Dialog.openTspDialog(pu,channelNo) 语句用到的 openTspDialog里面调用了 BVCU.cs 中的 DllImport 的 ManagedLayer_CuOpenTspDialog,参见BVCU.cs:
[DllImport("ManagedLayer.dll", CallingConvention = CallingConvention.Cdecl)]publicstatic extern int ManagedLayer_CuOpenTspDialog(IntPtr handle, refIntPtr dialog, IntPtrsession, Byte[] puId, int channelNo,
EventHandler.BVCU_TspDialog_OnEvent onDlgEvent, EventHandler.BVCU_TspDialog_OnDataonDlgData);
以下代码位于Form1.cs中:
/*
* 双击界面上的资源树打开对话
*/
const int TREE_LEVEL_SESSION = 0;
const int TREE_LEVEL_PU = 1;
const int TREE_LEVEL_CHANNEL = 2;
privatevoid treeViewResList_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgse)
{
……略过已有代码,else if 是修改的代码,只修改了 if 条件
elseif (channelNo >= BVCU.BVCU_SUBDEV_INDEXMAJOR_MIN_GPS&& channelNo < BVCU.BVCU_SUBDEV_INDEXMAJOR_MAX_GPS)
{
……未修改
}
//此处为添加的代码
else
{
if(m_sdkOperator.Dialog.openTspDialog(pu, channelNo) == 0)
{
ListViewItem item = new ListViewItem();
item.Text = pu.id;
item.Tag = channelNo;
ListViewItem.ListViewSubItemTspData = new ListViewItem.ListViewSubItem();
ListViewItem.ListViewSubItemlen = new ListViewItem.ListViewSubItem();
item.SubItems.AddRange(new ListViewItem.ListViewSubItem[] { TspData, len });
listViewGPSData.Items.Add(item);
}
}
}
}
openTspDialog 位于 Dialog.cs 中:
ArrayList m_tspDialogs;
public int openTspDialog(Session.Pu pu, intchannelNo)
{
foreach(OneDialog dlg inm_tspDialogs)
{
if(dlg.pu.id.Equals(pu.id, StringComparison.CurrentCultureIgnoreCase)
&& dlg.channelNo ==channelNo)
{
return-1;
}
}
IntPtrdialog = IntPtr.Zero;
//此处为调用的 ManagedLayer_CuOpenTspDialog
if(BVCU.ManagedLayer_CuOpenTspDialog(m_bvsdkHandle,ref dialog, m_session.Handle, Encoding.UTF8.GetBytes(pu.id),
channelNo,m_bvsdkEventHandler.tspDialog_OnEvent, m_bvsdkEventHandler.tspDialog_OnData)
== BVCU.BVCU_RESULT_S_OK)
{
OneDialogdlg = new OneDialog();
dlg.dialogHandle = dialog;
dlg.channelNo = channelNo;
dlg.pu = pu;
m_tspDialogs.Add(dlg);
return0;
}
return-1;
}
2.3 m_bvsdkEventHandler.tspDialog_OnEvent/ tspDialog_OnData回调 EventHandle.cs中:
public delegate void BVCU_TspDialog_OnEvent(IntPtrdialog, int eventCode, Int32errorCode);
public delegate void BVCU_TspDialog_OnData(IntPtrdialog, string pTspData, int len);
public BVCU_TspDialog_OnData tspDialog_OnData;
public BVCU_TspDialog_OnEvent tspDialog_OnEvent;
voidTspDialog_OnEvent(IntPtr dialog, int eventCode, Int32errorCode)
{
if(errorCode != BVCU.BVCU_RESULT_S_OK)
{
m_dialog.onTspDialogOpenFailed(dialog);
}
}
voidTspDialog_OnData(IntPtr dialog, string pTspData, intlen)
{
//以下在 Dialog.cs 中
m_dialog.onTspData(dialog,pTspData, len);
}
Dialog.cs 中:
delegate void OnGetTspData(IntPtr dialog, stringpTspData, int len);
OnGetTspDatadeleGetTspData;
public void onTspData(IntPtrdialog, string pTspData, int len)
{
if(null == deleGetTspData)
{
deleGetTspData = new OnGetTspData(procGetTspData);
}
m_mainForm.BeginInvoke(deleGetTspData, newobject[] { dialog, pTspData, len });
}
voidprocGetTspData(IntPtr dialog, string pTspData, intlen)
{
foreach (OneDialog dlg inm_tspDialogs)
{
if(dlg.dialogHandle == dialog)
{
m_mainForm.onGetTspData(dlg.pu.id, pTspData, len);
return;
}
}
}
2.4显示 TSPForm1.cs中:
public void onGetTspData(string puId, string pTspData, int len)
{
foreach(ListViewItem item inlistViewGPSData.Items)
{
if(item.Text.Equals(puId, StringComparison.CurrentCultureIgnoreCase))
{
ListViewItem.ListViewSubItem TspData = newListViewItem.ListViewSubItem();
TspData.Text = pTspData;
item.SubItems[1] = TspData;
ListViewItem.ListViewSubItem length = newListViewItem.ListViewSubItem();
length.Text =len.ToString();
item.SubItems[2] = length;
return;
}
}
}
2.5底层支持载入的 ManagedLayer_CuOpenTspDialog 位于工程 ManagedLayer.cpp 中,我在里面添加了这个函数,具体请参考工程代码,ManagedLayer_CuOpenTspDialog 调用了 CBVCU.cpp 中的 openTspDialog,openTspDialog 指定了 dlgParam.OnEvent = tspDialog_OnEvent; 和 dlgParam.afterDecode = tspDialog_OnData; 作为 Tsp 的事件回调和解码回调,这两个回调定义于 CBVCU.cpp 中。
intCBVCU:penTspDialog(BVCU_HDialog* dlg, BVCU_HSession session, char* puId, intchannelNo, BVCU_TspDialog_OnEventonDlgEvent, BVCU_TspDialog_OnData onDlgData)
{
BVCU_DialogParamdlgParam;
BVCU_DialogControlParamdlgCtlParam;
memset(&dlgParam,0, sizeof(dlgParam));
memset(&dlgCtlParam,0, sizeof(dlgCtlParam));
dlgParam.iSize= sizeof(dlgParam);
dlgCtlParam.iSize= sizeof(dlgCtlParam);
dlgParam.hSession= session;
BVCU_DialogTargettarget;
strncpy_s(target.szID,BVCU_MAX_ID_LEN+1,puId,_TRUNCATE);
// memset(&target,0, sizeof(BVCU_DialogTarget));
target.iIndexMajor= channelNo;
// strcpy_s(target.szID,BVCU_MAX_ID_LEN + 1, puId);
target.iIndexMinor= -1;
dlgParam.iTargetCount= 1;
dlgParam.pTarget= ⌖
dlgParam.iAVStreamDir= BVCU_MEDIADIR_DATARECV;
dlgParam.OnEvent= tspDialog_OnEvent;
dlgParam.afterDecode= tspDialog_OnData;
if (NULL == m_procGpsDialogEvent)
{
m_procTspDialogEvent= onDlgEvent;
}
if (NULL == m_procGpsDialogOnData)
{
m_procTspDialogOnData= onDlgData;
}
// <TODO>: 参考MLibBVCU.cpp
return BVCU_Dialog_Open(dlg, &dlgParam,&dlgCtlParam);
}
总结:有了MFCDemo例程,其他的都不是很难,只需仿照就行了。
author: besovideo time: 2018-3-29 12:23
其它一些测试工具的说明,可不用写代码,直接用管理器测试透明串口的通信。
附上相关文档和图片说明。
欢迎光临 mobile CCTV,mobile surveillance,police body worn cameras (http://bbs.besovideo.com:8067/) |
Powered by Discuz! X3.2 |