using Admin.Core.Common;
using log4net;
using MvCodeReaderSDKNet;
using NPOI.SS.Formula.Functions;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Text;
using UAParser;
using static System.Runtime.CompilerServices.RuntimeHelpers;
namespace Aucma.Core.Scanner
{
public class MvCodeHelper
{
#region 委托事件
#region 条码绑定上位机委托事件
///
/// code1扫码信息刷新
///
///
public delegate void ReceiveCode1(string code1);
public static event ReceiveCode1? ReceiveCode1Event;
///
/// code2扫码信息刷新,记录表更新
///
///
public delegate void ReceiveCode2(string code2);
public static event ReceiveCode2? ReceiveCode2Event;
#endregion
#region 成品下线上位机委托事件
///
/// code扫码信息刷新
///
///
public delegate void ReceiveCode(string code, int scannerNo);
public static event ReceiveCode? ReceiveCodeEvent;
public static bool m_bGrabbing = true;
#endregion
#endregion
private static readonly log4net.ILog log = LogManager.GetLogger(typeof(MvCodeHelper));
// 获取到的所有设备
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 static 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
{
log.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)
{
log.Info("获取扫码器列表失败,扫码器错误码:" + nRet);
return;
}
if (0 == m_stDeviceList.nDeviceNum)
{
log.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}");
log.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)
{
log.Error("创建第" + i + "个扫码器设备失败,ip:" + ip);
return;
}
log.Info("创建第" + i + "个扫码器设备成功,ip:" + ip);
// 打开设备
nRet = m_cMyDevice.MV_CODEREADER_OpenDevice_NET();
if (MvCodeReader.MV_CODEREADER_OK != nRet)
{
m_cMyDevice.MV_CODEREADER_DestroyHandle_NET();
log.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)
{
log.Error("Set TriggerMode On Fail!");
return;
}
//添加到集合
m_cMyDevices.Add(m_cMyDevice, ip);
/**
nRet = m_cMyDevice.MV_CODEREADER_OpenDevice_NET();//打开设备
if (MvCodeReader.MV_CODEREADER_OK != nRet)
{
log.Error("打开第" + i + "个扫码器设备失败,销毁设备,ip:" + ip);
m_cMyDevice.MV_CODEREADER_DestroyHandle_NET();
return;
}
else
{
m_cMyDevices.Add(m_cMyDevice, ip);
log.Info("打开第" + i + "个扫码器设备成功,ip:" + ip);
}
// ch:设置触发模式为off || en:set trigger mode as off
if (MvCodeReader.MV_CODEREADER_OK != m_cMyDevice.MV_CODEREADER_SetEnumValue_NET("TriggerMode", 0))
{
log.Error("设置第" + i + "个扫码器设备触发模式失败,ip:" + ip);
return;
}
log.Info("第" + i + "个扫码器设备设置采集连续模式成功!ip:" + ip);
// ch:开启抓图 | en:start grab
nRet = m_cMyDevice.MV_CODEREADER_StartGrabbing_NET();
if (MvCodeReader.MV_CODEREADER_OK != nRet)
{
log.Error("设置第" + i + "个扫码器设备开启抓图失败,ip:" + ip);
return;
}
log.Info("*****************************************************************");
log.Info("第" + i + "个扫码器设备创建,打开,开启连续抓图设置成功!ip:" + ip);
**/
}
}
}
catch (Exception ex)
{
log.Error("获取和创建设备异常:" + ex);
}
}
#endregion
#region 开启扫描 取消使用
public static void StartGrab1()
{
try
{
// 所有已打开相机开始扫码
foreach (KeyValuePair hashmap in m_cMyDevices)
{
Task.Run(() =>
{
// 记录相机上一次扫描到的条码
string lastStr = string.Empty;
int nRet = MvCodeReader.MV_CODEREADER_OK;
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);
int nCount = 0;
while (true)
{
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);
log.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');
log.Info("相机ip:" + hashmap.Value + " Get CodeNum: " + "CodeNum[" + i.ToString() + "], CodeString[" + strCode + "]");
if (!string.IsNullOrEmpty(strCode))
{
if (strCode != lastStr)
{
// 处理业务
// 扫码器1,处理扫码器1的业务
if (hashmap.Value.Equals(Appsettings.app("Middleware", "Scanner1", "Ip")))
{
#region 条码绑定业务处理
ReceiveCode1Event?.Invoke(strCode);
#endregion
}
else if (hashmap.Value.Equals(Appsettings.app("Middleware", "Scanner2", "Ip"))) // 扫码器2,处理扫码器2的业务
{
#region 条码绑定业务处理
ReceiveCode2Event?.Invoke(strCode);
#endregion
}
}
lastStr = strCode;
}
}
}
}
Thread.Sleep(500);
}
});
}
}
catch (Exception ex)
{
log.Error("开启相机扫描异常:" + 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);
log.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');
log.Info("相机ip:" + hashmap.Value + " Get CodeNum: " + "CodeNum[" + i.ToString() + "], CodeString[" + strCode + "]");
if (!string.IsNullOrEmpty(strCode))
{
// 获取到条码处理业务
Console.WriteLine(strCode,hashmap.Value);
}
}
}
}
Thread.Sleep(500);
}
}
}
catch (Exception ex)
{
log.Error("扫码异常:" + ex);
}
}
#endregion
#region 关闭所有设备
public static void CloseAllDevice()
{
try
{
log.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)
{
log.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)
{
log.Error("设备ip:" + hashmap.Value + "关闭失败");
}
// ch:销毁设备 | en:Destroy device
nRet = hashmap.Key.MV_CODEREADER_DestroyHandle_NET();
if (MvCodeReader.MV_CODEREADER_OK != nRet)
{
log.Error("设备ip:" + hashmap.Value + "销毁失败");
}
log.Error("设备ip:" + hashmap.Value + "关闭成功!");
}
}
catch (Exception ex)
{
log.Error("设备关闭异常:" + ex);
}
}
#endregion
#region 关闭指定设备
public static 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)
{
log.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)
{
log.Error("设备ip:" + hashmap.Value + "关闭失败");
return;
}
}
catch (Exception ex)
{
log.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
}
}