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.
Aucma.Scada/Aucma.Scada.HikRobot/GrabImage.cs

333 lines
14 KiB
C#

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 storeCode,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.shellHikRobotIp)
{
Grab(i, stDevList, stDevInfo, device, appConfig.shellStoreCode);
continue;
}else if(ip == appConfig.linerHikRobotIp)
{
Grab(i, stDevList, stDevInfo, device, appConfig.linerStoreCode);
continue;
}
}
}
} while (false);
}
private void Grab(int index,MvCodeReader.MV_CODEREADER_DEVICE_INFO_LIST stDevList, MvCodeReader.MV_CODEREADER_DEVICE_INFO stDevInfo,MvCodeReader device,string storeCode)
{
try
{
Task.Run(() =>
{
string str = storeCode == appConfig.shellStoreCode ? "箱壳" : "内胆";
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($"{str}扫码器创建成功");
}
// 打开设备
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($"{str}扫码器打开成功");
}
// 设置触发模式为off
if (MvCodeReader.MV_CODEREADER_OK != device.MV_CODEREADER_SetEnumValue_NET("TriggerMode", 0))
{
Console.WriteLine("Set TriggerMode failed!");
break;
}
else
{
RefreshLogMessageEvent?.Invoke($"{str}扫码器设置触发模式为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($"{str}扫码器开启抓图");
}
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(storeCode, 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;
}
}
}