OKLE_WeightSensor.cs 15.0 KB
using log4net;
using OnlineStore;
using OnlineStore.Common;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DeviceLibrary
{

    public class OKLE_WeightSensor
    {
        SerialPort port;
        Thread thread;
        ILog loge;
        ushort seq = 0;
        public byte station = 1;

        public OKLE_WeightSensor(string logName= "RollingLogFileAppender")
        {
            this.loge = LogManager.GetLogger(logName);
            port = new SerialPort();
            port.BaudRate = 9600;
            port.Parity = Parity.None;
            port.DataBits = 8;
            port.StopBits = StopBits.One;
            port.ReadTimeout = 1000;
            port.WriteTimeout = 1000;
            thread = new Thread(new ThreadStart(Monitor));
            thread.Start();
        }
        void Monitor()
        { }

        public bool IsPortOpen { get => port == null ? false : port.IsOpen; }

        public void Close()
        {
            port.Close();
        }
        string PortName = "";

        #region 地址对应
        enum Addr
        {
            传感器灵敏度 = 46, //uint32    传感器灵敏度大小,免砝码标定用。范围:0.1mv/V~7.8mv/V,设置时无需输入小数点,比如灵敏度为2.0000mv/V,则写入20000(小数点后保留4位)
            传感器量程 = 48,  //uint32    传感器量程大小,免砝码标定用。如传感器量程为100kg,要精确到1g,则输入100000;(V1.1版固件以上支持)
            毛重 = 80,     //int32    实际毛重,负数采用标准补码方式
            最大称量 = 86,   //uint32    最大称量值;范围:0~8000000;使用称台功能前需先设置此值
            称台分度 = 88,   //uint16    称台分度值;使用称台功能前需先设置此值。0x00:0.0001   0x01:0.0002   0x02:0x0005
                         //0x03:0.001    0x04:0.002    0x05:0.005
                         //0x06:0.01     0x07:0.02     0x08;0.05
                         //0x09:0.1      0x0A:0.2      0x0B:0.5
                         //0x0C:1        0x0D:2        0x0E:5
                         //0x0F:10       0x10:20       0x11:50
            手动置零范围 = 93, //uint16  设置手动清零的范围;单位为满量程的百分比;写0后手动清零功能无效
            执行手动置零 = 94, //uint16  写入0x01后执行手动置零操作
            自动零位跟踪范围 = 96, //uint16 参数范围:0~10000;单位:0.1d;设置0时关闭零位跟踪功能

            清除峰谷值 = 290, //uint16  写入0x01后清除峰谷值
            峰值 = 291,    //int32
            峰值检测使能方式 = 295,  //uint16    0:关闭峰值检测;1:力值超过峰值阈值后启动峰值检测;2:由外部触发并满足峰值阈值后启动峰值检测
            比较器0使能方式 = 310,  //uint16    0:比较器停止;1:上电即启动比较器;2:外部信号启停比较器
            比较器0判断方式 = 311,  //uint16    比较器判断方式如下;0x00:力值>上限    0x01:中限<力值≤上限   0x02:下限<力值≤中限  0x03:力值≤下限   0x04:力值>上限 下限<力值≤中限 0x05:力值>上限 力值≤下限    0x06:力值≤下限 中限<力值≤上限
            比较器0数据来源 = 312,  //uint16    比较器数据来源如下;0x00:测量值  0x01:毛重; 0x02:净重;0x03:峰值;  0x04:谷值; 0x05:峰值-谷值
            比较器0判断延时 = 313,  //uint16    比较器判断延时时间;单位0.1秒
            上限比较值0 = 314,  //uint32    设置上限值大小
        }

        #endregion
        public bool Open(string portName, out string msg)
        {
            try
            {
                msg = "";
                PortName = portName;
                port = new SerialPort();
                port.BaudRate = 9600;
                port.Parity = Parity.None;
                port.DataBits = 8;
                port.StopBits = StopBits.One;
                port.ReadTimeout = 1000;
                port.WriteTimeout = 1000;
                port.PortName = PortName;
                port.Open();
                if (!port.IsOpen)
                {
                    msg += crc.GetString("comOpenFail", "串口{0}打开失败", PortName);
                    //msg = "端口连接失败:" + PortName;
                    log("串口打开失败:" + PortName.ToString());
                    return false;
                }
                else
                { 
                    LogUtil.info("压力传感器" + PortName + "打开成功");
                }
                Init();
                ReadAndLog();

                int v = Setting_Init.Device_WeightSensor_MaxValue;
                if(v > 0)
                {
                    SetAlarmWeight(v);
                    log("SetAlarmWeight=" + v);
                }

                log("GetWeight: " + GetWeight());
                return true;
            }
            catch (Exception e)
            {
                msg = crc.GetString("comOpenFail", "串口{0}打开失败", PortName);
                //msg =e.ToString();
                log("串口"+PortName+"打开失败:"+e.ToString());
                return false;
            }
        }
        double ReadInt32(Addr addr)
        {
            var ret = Read(addr, 2);
            if (ret.Length > 7)
            {
                var b = new byte[] { ret[6], ret[5], ret[4], ret[3] };
                return ((double)BitConverter.ToInt32(b, 0)) / 100;
            }
            return double.MinValue;
        }
        short ReadShort(Addr addr)
        {
            var ret = Read(addr, 1);
            if (ret.Length >= 7)
            {
                var b = new byte[] { ret[4], ret[3] };
                return BitConverter.ToInt16(b, 0);
            }
            return -1;
        }
        byte[] Read(Addr addr, int quantity)
        {
            var seqhead = BitConverter.GetBytes(seq);
            var addrbyte = BitConverter.GetBytes((uint)addr);
            var quantitybyte = BitConverter.GetBytes(quantity);
            byte[] by = new byte[]
            {
            station,
            0x03,
            //读地址
            addrbyte[1],
            addrbyte[0],
            //读数量
            quantitybyte[1],
            quantitybyte[0],
            0x00,
            0x00

            };
            CalculateCRC(by, by.Length - 2, out ushort checksun);

            var crcbyte = BitConverter.GetBytes(checksun);
            by[by.Length - 2] = crcbyte[0];
            by[by.Length - 1] = crcbyte[1];
            log(addr.ToString() + "\treaddata: " + BitConverter.ToString(by).Replace("-", " "));
            return SendAndReceive(by, addr.ToString());
        }
        bool WriteUShort(Addr addr, ushort value)
        {
            var b = BitConverter.GetBytes(value);
            b = b.Reverse().ToArray();
            var ret = Write(addr, b);
            return ret.Length > 0;
        }
        bool WriteUInt(Addr addr, uint value)
        {
            var b = BitConverter.GetBytes(value);
            b = b.Reverse().ToArray();
            var ret = Write(addr, b);
            return ret.Length > 0;
        }
        byte[] Write(Addr addr, byte[] value)
        {
            var seqhead = BitConverter.GetBytes(seq);
            var addrbyte = BitConverter.GetBytes((uint)addr);
            byte[] by2 = new byte[]
            {
            station,
            0x10,
            //读地址
            addrbyte[1],
            addrbyte[0],
            //要写入的寄存器数量
            0x00,
            (byte)(value.Length/2),
            //数据字节计数,表示后面要写入的数据字节数
            (byte)value.Length,
            };
            var by3 = by2.ToList();
            by3.AddRange(value);
            by3.AddRange(new byte[] { 0x00, 0x00 });
            var by = by3.ToArray();
            CalculateCRC(by, by.Length - 2, out ushort checksun);

            var crcbyte = BitConverter.GetBytes(checksun);
            by[by.Length - 2] = crcbyte[0];
            by[by.Length - 1] = crcbyte[1];
            log(addr.ToString() + "\twritedata: " + BitConverter.ToString(by).Replace("-", " "));
            return SendAndReceive(by, addr.ToString());
        }
        byte[] SendAndReceive(byte[] buff, string cmdname = "")
        {
            lock (port)
            {
                byte[] restr = new byte[0];
                if (port == null || !port.IsOpen)
                {
                    if (!Open(PortName,out string msg))
                    {
                        log(PortName+"未初始化,或已断开连接");
                        return restr;
                    }
                }
                var t = Task.Run(delegate
                {
                    byte[] recv = new byte[256];
                    try
                    {
                        port.Write(buff, 0, buff.Length);
                        //port.DiscardInBuffer();
                        Thread.Sleep(60);
                        int r = port.Read(recv, 0, recv.Length);
                        var recvdata = recv.Take(r).ToArray();
                        port.DiscardOutBuffer();
                        port.DiscardInBuffer();
                        CalculateCRC(recvdata, recvdata.Length - 2, out ushort checksun);
                        var crcbyte = BitConverter.GetBytes(checksun);
                        debuglog(cmdname + "\trecvdata: " + BitConverter.ToString(recvdata).Replace("-", " ") + " crc:" + BitConverter.ToString(crcbyte).Replace("-", " "));
                        if (recvdata.Length > 5
                        && recvdata[1] == buff[1]
                        && recvdata[recvdata.Length - 2] == crcbyte[0]
                        && recvdata[recvdata.Length - 1] == crcbyte[1])
                        {
                            return recvdata;
                        }
                        return restr;
                    }
                    catch (SocketException e)
                    {
                        log(string.Format("{0} Error code: {1}.", e.Message, e.ErrorCode));
                    }
                    return restr;
                });
                t.Wait(2000);
                if (t.IsCompleted)
                    return t.Result;
                else
                    return new byte[0];
            }
        }
        /// <summary>
        /// 初始化设置
        /// </summary>
        /// <returns></returns>
        public bool Init()
        {
            if (!WriteUInt(Addr.传感器灵敏度, 4202))
                return false;
            if (!WriteUInt(Addr.传感器量程, 1000))
                return false;
            if (!WriteUInt(Addr.最大称量, 1000))
                return false;
            if (!WriteUShort(Addr.称台分度, 6))
                return false;
            if (!WriteUShort(Addr.峰值检测使能方式, 1))
                return false;
            if (!WriteUShort(Addr.比较器0使能方式, 1))
                return false;
            if (!WriteUShort(Addr.比较器0判断方式, 0))
                return false;
            if (!WriteUShort(Addr.比较器0数据来源, 0))
                return false;
            if (!WriteUShort(Addr.比较器0判断延时, 0))
                return false;

            if (!WriteUShort(Addr.手动置零范围, 100))
                return false;


            return false;
        }

        public void ReadAndLog()
        {
            double lingmindu = ReadInt32(Addr.传感器灵敏度);
            loge.Info($"读取到灵敏度:{lingmindu}");
            double licheng = ReadInt32(Addr.传感器量程);
            loge.Info($"读取到传感器量程:{licheng}");
            double chengliang = ReadInt32(Addr.最大称量);
            loge.Info($"读取到最大称量:{chengliang}");
            double fendu = ReadShort(Addr.称台分度);
            loge.Info($"读取到称台分度:{fendu}");
            double fengzhi = ReadShort(Addr.峰值检测使能方式);
            loge.Info($"读取到峰值检测使能方式:{fengzhi}");
            double bijiaoqi = ReadShort(Addr.比较器0使能方式);
            loge.Info($"读取到比较器0使能方式:{bijiaoqi}");
            double panduan = ReadShort(Addr.比较器0判断方式);
            loge.Info($"读取到比较器0判断方式:{panduan}");
            double laiyuan = ReadShort(Addr.比较器0数据来源);
            loge.Info($"读取到比较器0数据来源:{laiyuan}");
            double yanchi = ReadShort(Addr.比较器0判断延时);
            loge.Info($"读取到比较器0判断延时:{yanchi}");
            double fanwei = ReadShort(Addr.手动置零范围);
            loge.Info($"读取到手动置零范围:{fanwei}");
        }
        /// <summary>
        /// 获取重量值
        /// </summary>
        /// <returns></returns>
        public double GetWeight()
        {
            return ReadInt32(Addr.毛重);
        }
        /// <summary>
        /// 重置尖峰重量值
        /// </summary>
        /// <returns></returns>
        public bool ResetPeakWeight()
        {
            return WriteUShort(Addr.清除峰谷值, 1);
        }
        /// <summary>
        /// 获取尖峰重量值
        /// </summary>
        /// <returns></returns>
        public double PeakWeight()
        {
            return ReadInt32(Addr.峰值);
        }
        /// <summary>
        /// 归零
        /// </summary>
        /// <returns></returns>
        public bool ResetZero()
        {
            return WriteUShort(Addr.执行手动置零, 1);
        }
        /// <summary>
        /// 设置报警阈值
        /// </summary>
        /// <returns></returns>
        public bool SetAlarmWeight(double kg)
        {
            return WriteUInt(Addr.上限比较值0, (uint)(kg * 100));
        }

        static void CalculateCRC(byte[] pByte, int nNumberOfBytes, out ushort pChecksum)
        {
            int nBit;
            ushort nShiftedBit;
            pChecksum = 0xFFFF;

            for (int nByte = 0; nByte < nNumberOfBytes; nByte++)
            {
                pChecksum ^= pByte[nByte];
                for (nBit = 0; nBit < 8; nBit++)
                {
                    if ((pChecksum & 0x1) == 1)
                    {
                        nShiftedBit = 1;
                    }
                    else
                    {
                        nShiftedBit = 0;
                    }
                    pChecksum >>= 1;
                    if (nShiftedBit != 0)
                    {
                        pChecksum ^= 0xA001;
                    }
                }
            }
        }
        void log(string msg)
        {
            loge.Info("WeightSensor:" + msg);
            Console.WriteLine(msg);
        }
        void debuglog(string msg)
        {
            loge.Debug("WeightSensor:" + msg);
            Console.WriteLine(msg);
        }
    }
}