using MvCodeReaderSDKNet; using System; using System.Collections.Generic; using System.Drawing; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Threading; using static System.Runtime.CompilerServices.RuntimeHelpers; using HighWayIot.Log4net; using HighWayIot.Config; using System.Security.Policy; namespace Aucma.Core.Scanner { public class MvCodeHelper { private static AppConfig appConfig = AppConfig.Instance; public static bool m_bGrabbing = true; #region 委托事件 public delegate void RefreshMaterialCodeStr(string storeCode, string materialCodeStr); public static event RefreshMaterialCodeStr RefreshMaterialCodeStrEvent; /// /// 日志信息刷新 /// /// public delegate void RefreshLogMessage(string message); public static event RefreshLogMessage RefreshLogMessageEvent; #endregion // 获取到的所有设备 public static MvCodeReader.MV_CODEREADER_DEVICE_INFO_LIST m_stDeviceList = new MvCodeReader.MV_CODEREADER_DEVICE_INFO_LIST(); // (成功创建)连接上的设备和其ip(string)集合 public static Dictionary m_cMyDevices = new Dictionary(); #region 设备连接状态 /// /// 获取不到任务设备即连接失败 /// /// public bool ConnectionStatus(string ip) { // 遍历所有已打开相机 foreach (KeyValuePair hashmap in m_cMyDevices) { if (ip.Equals(hashmap.Value)) { return true; } } // 没有连接上,重新获取并创建设备 Task.Run(() => { DeviceListAcq(); }); return false; } #endregion #region 获取并创建设备列表 /// /// 获取并创建设备列表 /// public static void DeviceListAcq() { try { RefreshLogMessageEvent?.Invoke("获取扫码器设备列表,进入DeviceListAcq()方法"); System.GC.Collect(); m_stDeviceList.nDeviceNum = 0; // 获取设备列表 int nRet = MvCodeReader.MV_CODEREADER_EnumDevices_NET(ref m_stDeviceList, MvCodeReader.MV_CODEREADER_GIGE_DEVICE); if (0 != nRet) { RefreshLogMessageEvent?.Invoke("获取扫码器列表失败,扫码器错误码:" + nRet); return; } if (0 == m_stDeviceList.nDeviceNum) { RefreshLogMessageEvent?.Invoke("获取扫码器数量为0,请检查扫码器连接:"); return; } MvCodeReader m_cMyDevice = new MvCodeReader(); //创建所有设备 for (int i = 0; i < m_stDeviceList.nDeviceNum; i++) { MvCodeReader.MV_CODEREADER_DEVICE_INFO stDevInfo = (MvCodeReader.MV_CODEREADER_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[i], typeof(MvCodeReader.MV_CODEREADER_DEVICE_INFO)); if (stDevInfo.nTLayerType == MvCodeReader.MV_CODEREADER_GIGE_DEVICE) { IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(stDevInfo.SpecialInfo.stGigEInfo, 0); MvCodeReader.MV_CODEREADER_GIGE_DEVICE_INFO stGigEDeviceInfo = (MvCodeReader.MV_CODEREADER_GIGE_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MvCodeReader.MV_CODEREADER_GIGE_DEVICE_INFO)); // 获取ip string ip = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24) + "." + ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16) + "." + ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8) + "." + (stGigEDeviceInfo.nCurrentIp & 0x000000ff); // Console.WriteLine($"打印扫码设备信息,下标:{i};IP:{ip}"); Console.Write("扫码器设备[" + i + "],ip:" + ip); // 创建第i个设备 stDevInfo = (MvCodeReader.MV_CODEREADER_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[i], typeof(MvCodeReader.MV_CODEREADER_DEVICE_INFO)); nRet = m_cMyDevice.MV_CODEREADER_CreateHandle_NET(ref stDevInfo);//创建设备 if (MvCodeReader.MV_CODEREADER_OK != nRet) { Console.WriteLine("创建第" + i + "个扫码器设备失败,ip:" + ip); return; } // 打开设备 nRet = m_cMyDevice.MV_CODEREADER_OpenDevice_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { m_cMyDevice.MV_CODEREADER_DestroyHandle_NET(); Console.WriteLine("Device open fail!"); return; } RefreshLogMessageEvent?.Invoke("创建并打开第" + i + "个扫码器设备成功,ip:" + ip); //设置触发模式 nRet = m_cMyDevice.MV_CODEREADER_SetEnumValue_NET("TriggerMode", (uint)MvCodeReader.MV_CODEREADER_TRIGGER_MODE.MV_CODEREADER_TRIGGER_MODE_ON); if (MvCodeReader.MV_CODEREADER_OK != nRet) { Console.WriteLine("设置触发模式失败"); return; } //添加到集合 m_cMyDevices.Add(m_cMyDevice, ip); } } } catch (Exception ex) { Console.WriteLine("获取和创建设备异常:" + ex); } } #endregion #region 光电触发扫码器接收条码处理业务 public static void StartGrab() { try { int nRet = MvCodeReader.MV_CODEREADER_OK; // 3.开启抓图 int nCount = 0; IntPtr pData = IntPtr.Zero; MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2 stFrameInfoEx2 = new MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2(); IntPtr pstFrameInfoEx2 = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2))); Marshal.StructureToPtr(stFrameInfoEx2, pstFrameInfoEx2, false); foreach (KeyValuePair hashmap in m_cMyDevices) { nRet = hashmap.Key.MV_CODEREADER_StartGrabbing_NET(); while (m_bGrabbing) { // 光电触发了有图像 nRet = hashmap.Key.MV_CODEREADER_GetOneFrameTimeoutEx2_NET(ref pData, pstFrameInfoEx2, 1000); // ch:获取一帧图像 | en:Get one image if (MvCodeReader.MV_CODEREADER_OK == nRet) { stFrameInfoEx2 = (MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2)Marshal.PtrToStructure(pstFrameInfoEx2, typeof(MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2)); // 分配条码内存空间 MvCodeReader.MV_CODEREADER_RESULT_BCR_EX2 stBcrResult = (MvCodeReader.MV_CODEREADER_RESULT_BCR_EX2)Marshal.PtrToStructure(stFrameInfoEx2.UnparsedBcrList.pstCodeListEx2, 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 = System.Text.Encoding.Default.GetString(stBcrResult.stBcrInfoEx2[i].chCode); string strCode = Encoding.UTF8.GetString(stBcrResult.stBcrInfoEx2[i].chCode); // logHelper.Info("bIsValidUTF8:: 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).Trim().TrimEnd('\0'); RefreshLogMessageEvent?.Invoke("相机ip:" + hashmap.Value + " Get CodeNum: " + "CodeNum[" + i.ToString() + "], CodeString[" + strCode + "]"); if (!string.IsNullOrEmpty(strCode)) { // 获取到条码处理业务 if (appConfig.shellHikRobotIp == hashmap.Value) { RefreshMaterialCodeStrEvent?.Invoke(appConfig.shellStoreCode, strCode); }else if(appConfig.linerHikRobotIp == hashmap.Value) { RefreshMaterialCodeStrEvent?.Invoke(appConfig.linerHikRobotIp, strCode); } } } } } Thread.Sleep(500); } } } catch (Exception ex) { Console.WriteLine("扫码异常:" + ex); } } #endregion #region 关闭所有设备 public static void CloseAllDevice() { try { Console.WriteLine("开始关闭所有设备"); int nRet = MvCodeReader.MV_CODEREADER_OK; // 关闭所有已打开相机 foreach (KeyValuePair hashmap in m_cMyDevices) { // ch:停止抓图 | en:Stop grab image nRet = hashmap.Key.MV_CODEREADER_StopGrabbing_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { Console.WriteLine("设备ip:" + hashmap.Value + "停止抓图失败"); Console.WriteLine("Stop grabbing failed{0:x8}", nRet); } // ch:关闭设备 | en:Close device nRet = hashmap.Key.MV_CODEREADER_CloseDevice_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { Console.WriteLine("设备ip:" + hashmap.Value + "关闭失败"); } // ch:销毁设备 | en:Destroy device nRet = hashmap.Key.MV_CODEREADER_DestroyHandle_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { Console.WriteLine("设备ip:" + hashmap.Value + "销毁失败"); } Console.WriteLine("设备ip:" + hashmap.Value + "关闭成功!"); } } catch (Exception ex) { Console.WriteLine("设备关闭异常:" + ex); } } #endregion #region 关闭指定设备 public void CloseDevice(KeyValuePair hashmap) { try { int nRet = MvCodeReader.MV_CODEREADER_OK; // ch:停止抓图 | en:Stop grab image nRet = hashmap.Key.MV_CODEREADER_StopGrabbing_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { Console.WriteLine("设备ip:" + hashmap.Value + "停止抓图失败"); Console.WriteLine("Stop grabbing failed{0:x8}", nRet); return; } // ch:关闭设备 | en:Close device nRet = hashmap.Key.MV_CODEREADER_CloseDevice_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { Console.WriteLine("设备ip:" + hashmap.Value + "关闭失败"); return; } } catch (Exception ex) { Console.WriteLine("设备关闭异常:" + ex); } } #endregion #region 判断字符编码 /// /// 判断字符编码 /// /// /// public static 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; } #endregion #region 将Byte转换为结构体类型 //将Byte转换为结构体类型 public static object ByteToStruct(byte[] bytes, Type type) { int size = Marshal.SizeOf(type); if (size > bytes.Length) { return null; } //分配结构体内存空间 IntPtr structPtr = Marshal.AllocHGlobal(size); //将byte数组拷贝到分配好的内存空间 Marshal.Copy(bytes, 0, structPtr, size); //将内存空间转换为目标结构体 object obj = Marshal.PtrToStructure(structPtr, type); //释放内存空间 Marshal.FreeHGlobal(structPtr); return obj; } #endregion } }