diff --git a/Aucma.Scada.HikRobot/MvCodeHelper.cs b/Aucma.Scada.HikRobot/MvCodeHelper.cs new file mode 100644 index 00000000..c957d480 --- /dev/null +++ b/Aucma.Scada.HikRobot/MvCodeHelper.cs @@ -0,0 +1,383 @@ +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 AppConfig appConfig = AppConfig.Instance; + public static bool m_bGrabbing = true; + private LogHelper logHelper = LogHelper.Instance; + #region 委托事件 + public delegate void RefreshMaterialCodeStr(string storeCode, string materialCodeStr); + public event RefreshMaterialCodeStr RefreshMaterialCodeStrEvent; + + + #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 void DeviceListAcq() + { + try + { + logHelper.Info("获取扫码器设备列表,进入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) + { + logHelper.Info("获取扫码器列表失败,扫码器错误码:" + nRet); + return; + } + + if (0 == m_stDeviceList.nDeviceNum) + { + logHelper.Info("获取扫码器数量为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}"); + logHelper.Info("扫码器设备[" + 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) + { + logHelper.Error("创建第" + i + "个扫码器设备失败,ip:" + ip); + return; + } + logHelper.Info("创建第" + i + "个扫码器设备成功,ip:" + ip); + // 打开设备 + nRet = m_cMyDevice.MV_CODEREADER_OpenDevice_NET(); + if (MvCodeReader.MV_CODEREADER_OK != nRet) + { + m_cMyDevice.MV_CODEREADER_DestroyHandle_NET(); + logHelper.Error("Device open fail!"); + return; + } + //设置触发模式 + 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) + { + logHelper.Error("Set TriggerMode On Fail!"); + return; + } + + //添加到集合 + m_cMyDevices.Add(m_cMyDevice, ip); + } + } + } + catch (Exception ex) + { + logHelper.Error("获取和创建设备异常:" + ex); + } + } + #endregion + + + #region 光电触发扫码器接收条码处理业务 + public 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'); + logHelper.Info("相机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) + { + logHelper.Error("扫码异常:" + ex); + } + } + #endregion + + + #region 关闭所有设备 + public void CloseAllDevice() + { + try + { + logHelper.Info("开始关闭所有设备"); + 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) + { + logHelper.Error("设备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) + { + logHelper.Error("设备ip:" + hashmap.Value + "关闭失败"); + + } + + // ch:销毁设备 | en:Destroy device + nRet = hashmap.Key.MV_CODEREADER_DestroyHandle_NET(); + if (MvCodeReader.MV_CODEREADER_OK != nRet) + { + logHelper.Error("设备ip:" + hashmap.Value + "销毁失败"); + } + logHelper.Error("设备ip:" + hashmap.Value + "关闭成功!"); + } + } + catch (Exception ex) + { + logHelper.Error("设备关闭异常:" + 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) + { + logHelper.Error("设备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) + { + logHelper.Error("设备ip:" + hashmap.Value + "关闭失败"); + return; + } + } + catch (Exception ex) + { + logHelper.Error("设备关闭异常:" + 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 + + + + } +} + + + + +