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 { /// /// 海康扫码器 /// public class GrabImage { #region 单例实现 private static readonly Lazy lazy = new Lazy(() => 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; /// /// 日志信息刷新 /// /// public delegate void RefreshLogMessage(string message); public event RefreshLogMessage RefreshLogMessageEvent; #endregion #region 私有变量 private List mvCodeReaders = new List(); 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(); } // 判断字符编码 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; } } }