|
|
|
|
using HighWayIot.Config;
|
|
|
|
|
using HighWayIot.Log4net;
|
|
|
|
|
using MvCodeReaderSDKNet;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace Aucma.Scada.HikRobot
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 海康扫码器
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class GrabImage
|
|
|
|
|
{
|
|
|
|
|
#region 单例实现
|
|
|
|
|
private static readonly Lazy<GrabImage> lazy = new Lazy<GrabImage>(() => new GrabImage());
|
|
|
|
|
public static GrabImage Instance
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return lazy.Value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 对象引用
|
|
|
|
|
private AppConfig appConfig = AppConfig.Instance;
|
|
|
|
|
private LogHelper logHelper = LogHelper.Instance;
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 委托事件
|
|
|
|
|
public delegate void RefreshMaterialCodeStr(string materialCodeStr);
|
|
|
|
|
public event RefreshMaterialCodeStr RefreshMaterialCodeStrEvent;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 日志信息刷新
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="message"></param>
|
|
|
|
|
public delegate void RefreshLogMessage(string message);
|
|
|
|
|
public event RefreshLogMessage RefreshLogMessageEvent;
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 私有变量
|
|
|
|
|
private List<MvCodeReader> mvCodeReaders = new List<MvCodeReader>();
|
|
|
|
|
|
|
|
|
|
private string lastStr = string.Empty;
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
private GrabImage()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
public void InitHikRobot()
|
|
|
|
|
{
|
|
|
|
|
int nRet = MvCodeReader.MV_CODEREADER_OK;
|
|
|
|
|
MvCodeReader device = new MvCodeReader();
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
// 枚举设备
|
|
|
|
|
MvCodeReader.MV_CODEREADER_DEVICE_INFO_LIST stDevList = new MvCodeReader.MV_CODEREADER_DEVICE_INFO_LIST();
|
|
|
|
|
nRet = MvCodeReader.MV_CODEREADER_EnumDevices_NET(ref stDevList, MvCodeReader.MV_CODEREADER_GIGE_DEVICE);
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_OK != nRet)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Enum device failed:{0:x8}", nRet);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
RefreshLogMessageEvent?.Invoke("海康扫码器初始化枚举设备信息,Enum device count : " + Convert.ToString(stDevList.nDeviceNum));
|
|
|
|
|
if (0 == stDevList.nDeviceNum)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MvCodeReader.MV_CODEREADER_DEVICE_INFO stDevInfo; // 通用设备信息
|
|
|
|
|
|
|
|
|
|
// 打印设备信息 ,选择指定IP的设备
|
|
|
|
|
for (Int32 i = 0; i < stDevList.nDeviceNum; i++)
|
|
|
|
|
{
|
|
|
|
|
stDevInfo = (MvCodeReader.MV_CODEREADER_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[i], typeof(MvCodeReader.MV_CODEREADER_DEVICE_INFO));
|
|
|
|
|
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_GIGE_DEVICE == stDevInfo.nTLayerType)
|
|
|
|
|
{
|
|
|
|
|
MvCodeReader.MV_CODEREADER_GIGE_DEVICE_INFO stGigEDeviceInfo = (MvCodeReader.MV_CODEREADER_GIGE_DEVICE_INFO)MvCodeReader.ByteToStruct(stDevInfo.SpecialInfo.stGigEInfo, typeof(MvCodeReader.MV_CODEREADER_GIGE_DEVICE_INFO));
|
|
|
|
|
string ip = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24) + "." + ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16) + "." + ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8) + "." + (stGigEDeviceInfo.nCurrentIp & 0x000000ff);
|
|
|
|
|
RefreshLogMessageEvent?.Invoke($"打印扫码设备信息,下标:{i};IP:{ip}");
|
|
|
|
|
if (ip == appConfig.foamHikRobotIp)
|
|
|
|
|
{
|
|
|
|
|
Grab(i, stDevList, stDevInfo, device);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} while (false);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Grab(int index,MvCodeReader.MV_CODEREADER_DEVICE_INFO_LIST stDevList, MvCodeReader.MV_CODEREADER_DEVICE_INFO stDevInfo,MvCodeReader device)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
int nRet = MvCodeReader.MV_CODEREADER_OK;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
stDevInfo = (MvCodeReader.MV_CODEREADER_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[index], typeof(MvCodeReader.MV_CODEREADER_DEVICE_INFO));
|
|
|
|
|
|
|
|
|
|
// 创建设备
|
|
|
|
|
nRet = device.MV_CODEREADER_CreateHandle_NET(ref stDevInfo);
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_OK != nRet)
|
|
|
|
|
{
|
|
|
|
|
RefreshLogMessageEvent?.Invoke($"Create device failed:{nRet}");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RefreshLogMessageEvent?.Invoke("泡后库扫码器创建成功");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 打开设备
|
|
|
|
|
nRet = device.MV_CODEREADER_OpenDevice_NET();
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_OK != nRet)
|
|
|
|
|
{
|
|
|
|
|
RefreshLogMessageEvent?.Invoke("Open device failed:{nRet}");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mvCodeReaders.Add(device);
|
|
|
|
|
RefreshLogMessageEvent?.Invoke("泡后库扫码器打开成功");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置触发模式为off
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_OK != device.MV_CODEREADER_SetEnumValue_NET("TriggerMode", 0))
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Set TriggerMode failed!");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RefreshLogMessageEvent?.Invoke("泡后库扫码器设置触发模式为off");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 开启抓图
|
|
|
|
|
nRet = device.MV_CODEREADER_StartGrabbing_NET();
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_OK != nRet)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Start grabbing failed:{0:x8}", nRet);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RefreshLogMessageEvent?.Invoke("泡后库扫码器开启抓图");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nCount = 0;
|
|
|
|
|
IntPtr pBufForDriver = IntPtr.Zero;
|
|
|
|
|
|
|
|
|
|
MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2 stFrameInfo = new MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2();
|
|
|
|
|
IntPtr pstFrameInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2)));
|
|
|
|
|
Marshal.StructureToPtr(stFrameInfo, pstFrameInfo, false);
|
|
|
|
|
|
|
|
|
|
while (nCount++ != 10)
|
|
|
|
|
{
|
|
|
|
|
nRet = device.MV_CODEREADER_GetOneFrameTimeoutEx2_NET(ref pBufForDriver, pstFrameInfo, 1000);
|
|
|
|
|
// 获取一帧图像
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_OK == nRet)
|
|
|
|
|
{
|
|
|
|
|
stFrameInfo = (MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2)Marshal.PtrToStructure(pstFrameInfo, typeof(MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2));
|
|
|
|
|
|
|
|
|
|
// 分配条码内存空间
|
|
|
|
|
MvCodeReader.MV_CODEREADER_RESULT_BCR_EX2 stBcrResult = (MvCodeReader.MV_CODEREADER_RESULT_BCR_EX2)Marshal.PtrToStructure(stFrameInfo.pstCodeListEx, typeof(MvCodeReader.MV_CODEREADER_RESULT_BCR_EX2));
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < stBcrResult.nCodeNum; ++i)
|
|
|
|
|
{
|
|
|
|
|
bool bIsValidUTF8 = IsTextUTF8(stBcrResult.stBcrInfoEx2[i].chCode);
|
|
|
|
|
if (bIsValidUTF8)
|
|
|
|
|
{
|
|
|
|
|
string strCode = Encoding.UTF8.GetString(stBcrResult.stBcrInfoEx2[i].chCode);
|
|
|
|
|
Console.WriteLine("Get CodeNum: " + "CodeNum[" + i.ToString() + "], CodeString[" + strCode.Trim().TrimEnd('\0') + "]");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
byte[] buffer = new byte[22];
|
|
|
|
|
if (stBcrResult.stBcrInfoEx2[i].chCode.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
Array.Copy(stBcrResult.stBcrInfoEx2[i].chCode, buffer, 22);
|
|
|
|
|
}
|
|
|
|
|
string strCode = Encoding.GetEncoding("UTF-8").GetString(buffer);
|
|
|
|
|
RefreshLogMessageEvent?.Invoke("Get CodeNum: " + "CodeNum[" + i.ToString() + "], CodeString[" + strCode.Trim().TrimEnd('\0') + "]");
|
|
|
|
|
if (!string.IsNullOrEmpty(strCode))
|
|
|
|
|
{
|
|
|
|
|
if(strCode != lastStr)
|
|
|
|
|
{
|
|
|
|
|
RefreshMaterialCodeStrEvent?.Invoke(strCode);
|
|
|
|
|
}
|
|
|
|
|
lastStr = strCode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("No data:{0:x8}", nRet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thread.Sleep(3000);
|
|
|
|
|
}
|
|
|
|
|
} while (false);
|
|
|
|
|
});
|
|
|
|
|
}catch(Exception ex)
|
|
|
|
|
{
|
|
|
|
|
logHelper.Error("扫码异常", ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ExitHikRobot()
|
|
|
|
|
{
|
|
|
|
|
int nRet = MvCodeReader.MV_CODEREADER_OK;
|
|
|
|
|
foreach (var device in mvCodeReaders)
|
|
|
|
|
{
|
|
|
|
|
// 停止抓图
|
|
|
|
|
nRet = device.MV_CODEREADER_StopGrabbing_NET();
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_OK != nRet)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Stop grabbing failed{0:x8}", nRet);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 关闭设备
|
|
|
|
|
nRet = device.MV_CODEREADER_CloseDevice_NET();
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_OK != nRet)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Close device failed{0:x8}", nRet);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 销毁设备
|
|
|
|
|
nRet = device.MV_CODEREADER_DestroyHandle_NET();
|
|
|
|
|
if (MvCodeReader.MV_CODEREADER_OK != nRet)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Destroy device failed:{0:x8}", nRet);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mvCodeReaders = new List<MvCodeReader>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 判断字符编码
|
|
|
|
|
private bool IsTextUTF8(byte[] inputStream)
|
|
|
|
|
{
|
|
|
|
|
int encodingBytesCount = 0;
|
|
|
|
|
bool allTextsAreASCIIChars = true;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < inputStream.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
byte current = inputStream[i];
|
|
|
|
|
|
|
|
|
|
if ((current & 0x80) == 0x80)
|
|
|
|
|
{
|
|
|
|
|
allTextsAreASCIIChars = false;
|
|
|
|
|
}
|
|
|
|
|
// First byte
|
|
|
|
|
if (encodingBytesCount == 0)
|
|
|
|
|
{
|
|
|
|
|
if ((current & 0x80) == 0)
|
|
|
|
|
{
|
|
|
|
|
// ASCII chars, from 0x00-0x7F
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((current & 0xC0) == 0xC0)
|
|
|
|
|
{
|
|
|
|
|
encodingBytesCount = 1;
|
|
|
|
|
current <<= 2;
|
|
|
|
|
|
|
|
|
|
// More than two bytes used to encoding a unicode char.
|
|
|
|
|
// Calculate the real length.
|
|
|
|
|
while ((current & 0x80) == 0x80)
|
|
|
|
|
{
|
|
|
|
|
current <<= 1;
|
|
|
|
|
encodingBytesCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Invalid bits structure for UTF8 encoding rule.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Following bytes, must start with 10.
|
|
|
|
|
if ((current & 0xC0) == 0x80)
|
|
|
|
|
{
|
|
|
|
|
encodingBytesCount--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Invalid bits structure for UTF8 encoding rule.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (encodingBytesCount != 0)
|
|
|
|
|
{
|
|
|
|
|
// Invalid bits structure for UTF8 encoding rule.
|
|
|
|
|
// Wrong following bytes count.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Although UTF8 supports encoding for ASCII chars, we regard as a input stream, whose contents are all ASCII as default encoding.
|
|
|
|
|
return !allTextsAreASCIIChars;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|