微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C#骏鹏自动售货机接口

MachineJP类:

第1部分:串口初始化,串口数据读写

using System;
 System.Collections.Generic;
 System.IO.Ports;
 System.Linq;
 System.Text;
 System.Threading;
 System.Threading.Tasks;
 System.Windows.Forms;
 MachineJPDll.Models;
 MachineJPDll.Utils;

namespace MachineJPDll
{
    /// <summary>
    /// 售货机接口(骏鹏接口)
    </summary>
    public partial class MachineJP
    {
        #region 变量
        <summary>
         串口资源
        </summary>
        private SerialPort m_SerialPort = null;
         待发送给串口的命令列表
        private List<Cmd> m_CommandList = new List<Cmd>();
         等待ACK_RPT或NAK_RPT的PC端向VMC端发送的消息列表
        private List<MT> m_WaitResultMTList = new List<MT> 从串口接收的数据集合(数据已通过验证)
        private ReceiveDataCollection m_ReceiveDataCollection = new ReceiveDataCollection();
        #endregion

        #region 构造函数与析构函数
         售货机接口(骏鹏接口)
        public MachineJP()
        {

        }

        ~MachineJP()
        {
            if (m_SerialPort != )
            {
                m_SerialPort.Close();
                m_SerialPort.dispose();
                m_SerialPort = ;
            }
        }
        #region 读取串口数据
         读取串口数据
        </summary>
        <returns>从串口读取的数据</returns>
        private byte[] ReadPort()
        {
            //读取串口数据
            DateTime dt = DateTime.Now;
            while (m_SerialPort.BytesToRead < 2)
            {
                Thread.Sleep(1);

                if (DateTime.Now.Subtract(dt).TotalMilliseconds > 1500) 超时
                {
                    return new byte[0];
                }
            }
            List<byte> recList = new List<byte>();
            byte[] recData = [m_SerialPort.BytesToRead];
            m_SerialPort.Read(recData,,recData.Length);
            recList.AddRange(recData);
            int length = recData[1] + 2; 报文数据总长度
            while (recList.Count < length)
            {
                if (m_SerialPort.BytesToRead > )
                {
                    recData = [m_SerialPort.BytesToRead];
                    m_SerialPort.Read(recData,recData.Length);
                    recList.AddRange(recData);
                }
                Thread.Sleep();
            }

            return recList.ToArray();
        }
        #region 向串口发送数据
          向串口发送数据
        <param name="cmd">待发送的命令</param>
        <param name="SN">序列号</param>
        void WritePort(Cmd cmd, SN)
        {
            发送数据
            List<byte> sendData = cmd.Data;
            sendData[1] = ()sendData.Count;
            sendData[2] = SN;
            byte[] checkCode = CommonUtil.CalCheckCode(sendData,sendData.Count);
            sendData.AddRange(checkCode);
            if (cmd.Mt != )
            {
                m_WaitResultMTList.Add(cmd.Mt);
            }
            m_SerialPort.Write(sendData.ToArray(),sendData.Count);
            LogHelper.Log(LogMsgType.Info,true#region 发送ACK消息
         发送ACK消息
        void SendACK( SN)
        {
            List<byte> sendData = byte>() { 0xE5,0x00,1)">0x40,1)">0x80 };
            WritePort( Cmd(sendData),SN);
        }
        #region Init 初始化
         初始化
        <param name="com">串口号(例:COM1)void Init(string com)
        {
            if (m_SerialPort == )
            {
                m_SerialPort = new SerialPort(com,1)">9600,Parity.None,1)">81024;
                m_SerialPort.WriteBufferSize = ;
                m_SerialPort.DataReceived +=  SerialDataReceivedEventHandler(serialPort_DataReceived);
            }

            if (!m_SerialPort.IsOpen)
            {
                m_SerialPort.open();
            }

            GET_SETUP();
            CONTROL_IND(0x13,1)">byte[] { 0x00 }); 初始化完成标志
            GET_STATUS();

            SetDecimalPlaces(2); 设置小数点位数
        }
        #region Close 关闭连接
         关闭连接
        void Close()
        {
            m_SerialPort.Close();
        }
        #region 接收串口数据
         接收串口数据
        <param name="type">消息类型<param name="subtype">消息子类型byte[] Receive(byte type,1)"> subtype)
        {
             m_ReceiveDataCollection.Get(type,subtype);
        }

        byte[] WaitReceive( subtype)
        {
            DateTime time =while ()
            {
                byte[] receiveData =if (receiveData != null)  receiveData;

                if (DateTime.Now.Subtract(time).TotalMinutes > 3) ;

                Thread.Sleep(50);
            }
        }

         type)
        {
            DateTime time = m_ReceiveDataCollection.Get(type);
                );
            }
        }
        #region 判断消息是否发送成功
         判断消息是否发送成功
        bool SendSuccess(3)
                {
                    false;
                }
                byte[] ack =byte[] nak =if (ack != ;
                if (nak != #endregion

    }
}
View Code

第2部分:接收串口数据,并响应货机,向货机发送数据

/*
 * VMC->PC数据的接收,货机事件的分发
 */

 MachineJPDll
{
    #region serialPort_DataReceived
         数据接收事件的方法
        void serialPort_DataReceived(object obj,SerialDataReceivedEventArgs args)
        {
             ReadPort();

            if (CommonUtil.ValidReceiveData(receiveData)) 只处理验证正确的数据,不正确的数据抛弃不处理
            {
                LogHelper.Log(LogMsgType.Info,receiveData);
                byte SN = CommonUtil.GetSN(receiveData);
                MT mt =  MT(receiveData);

                #region 轮询(POLL)
                if (mt.Type == 0x03if (m_CommandList.Count > )
                    {
                        WritePort(m_CommandList[],SN);
                        m_CommandList.RemoveAt();
                    }
                    else
                    {
                        发送ACK消息
                        SendACK(SN);
                    }
                }
                #endregion

                #region 发送ACK消息
                if (CommonUtil.NeedACK(receiveData))
                {
                    SendACK(SN);                 }
                #region VMC系统参数
                0x05)
                {
                    m_ReceiveDataCollection.Add(mt.Type,mt.Subtype,receiveData);
                }
                #region ACK_RPT或NAK_RPT
                0x01 ACK_RPT
                    || mt.Type == 0x02) NAK_RPT
if (m_WaitResultMTList.Count > )
                    {
                        m_ReceiveDataCollection.Add(m_WaitResultMTList[0].Type,m_WaitResultMTList[].Subtype,receiveData);
                        m_WaitResultMTList.RemoveAt();
                    }
                }
                #region INFO_RPT 数据报告
                0x11#region 纸币器信息
                    if (mt.Subtype == 16)
                    {
                        m_ReceiveDataCollection.Add(mt.Type,receiveData);
                    }
                    #endregion

                    #region 硬币器信息
                    17#region 用户投币余额
                    
                }
                #region vendOUT_RPT 出货报告
                0x08#region STATUS_RPT VMC整机状态报告
                0x0D#region SALEPRICE_IND 设置当前商品售价
                0x8E#region PAYIN_RPT VMC发送现金投币报告给PC
                0x06#region PAYOUT_RPT 出币报告
                0x07#region COST_RPT VMC扣款报告
                0x10#region ACTION_RPT 售货机行为报告
                0x0B#region HUODAO_RPT VMC货道报告
                0x0E
            }
            else 接收到的数据没有验证通过
            {
                LogHelper.LogException(LogMsgType.Error,1)">false,1)">"数据异常"

    }
}
View Code

第3部分:货机状态、投币、出货等接口

 MachineJPDll.Enums;

 * PC->VMC数据的发送(并非直接发送,只是添加到发送列表)
 #region GET_SETUP
         PC通知VMC发送VMC_SETUP
         VmcSetup GET_SETUP()
        {
            List<0x90 };
            m_CommandList.Add( Cmd(sendData));

            byte[] receiveData = WaitReceive();
             VmcSetup(receiveData);
            }
            ;
        }
        #region CONTROL_IND PC控制售货机完成对应的动作
         PC控制VMC
        bool CONTROL_IND(byte subtype,1)">[] value)
        {
            List<0x41,1)">0x85 };
            sendData.Add(subtype);
            if (value != null && value.Length > )
            {
                sendData.AddRange(value);
            }
            m_CommandList.Add(new Cmd(sendData,1)"> MT(sendData)));

            return SendSuccess(#region 设置小数点位数
         设置小数点位数
         用于PC 通知VMC,双方的金额数据比例系数关系,PC 每次启动时,都会给
         VMC 下发一次type=18 的消息,VMC 需要自己永久保存该数据,直到被PC 再
         次更新。
         取值范围:0、1、2 分别表示以 元、 角 、分 为单位
        bool SetDecimalPlaces(int data)
        {
            return CONTROL_IND(18,1)">byte[] { ()data });
        }
        #region GET_STATUS PC通知VMC发送STATUS_RPT
         PC通知VMC发送STATUS_RPT
         StatusRpt GET_STATUS()
        {
            List<0x86 StatusRpt(receiveData);
            }
            #region GET_INFO PC通知VMC发送INFO_RPT
         PC通知VMC发送INFO_RPT
        byte[] GET_INFO( subtype)
        {
            List<0x8C };
            sendData.Add(subtype);
            m_CommandList.Add(return WaitReceive();
        }
        #region vendOUT_IND 出货
         PC出货指示
        <param name="device">售货机的箱体号 例如柜1 为 0x01 以此类推<param name="method">method =1:VMC 通过商品ID 指示出货,如果商品ID 不存在,回复NAK_RPT method =2:VMC 通过货道ID 指示VMC 出货,如果货道ID 不存在,回复NAK_RPT<param name="sp_id_hd_id">sp_id:通过商品ID 指示VMC 出货 hd_id:通过货道ID 指示VMC 出货如果type=0,cost 代表本次出货扣款金额 如果TYPE 不为0,则COST 必须为0<param name="cost">cost 代表本次出货扣款金额public vendoutRpt vendOUT_IND(byte device,1)">byte method,1)">byte sp_id_hd_id,1)"> cost)
        {
            List<0x83 };
            sendData.AddRange([] { device,method,sp_id_hd_id,type });
            sendData.AddRange(CommonUtil.Int2ByteArray(cost,1)">));
            m_CommandList.Add(if (SendSuccess(0x83,1)">0x00))
            {
                );
                 vendoutRpt(receiveData);
                }
            }
            #region HUODAO_SET_IND 设置货道商品数量
         PC通知VMC,当前货道对应商品的数量等信息
        表示箱柜号<param name="huodao">zyxxxxxx “z”固定填0 “y”固定填0 “xxxxxx”,表示商品余量,如果商品余量大于63,则统一为63bool HUODAO_SET_IND(int> huodao)
        {
            List<0x8F };
            sendData.Add(device);
            for (int i = 0; i < huodao.Count; i++if (huodao[i] > 63)
                {
                    huodao[i] = ;
                }
            }
            sendData.AddRange(huodao.ConvertAll<byte>(a => ()a));
            m_CommandList.Add(0x8F,1)">#region SALEPRICE_IND 设置当前商品售价
         PC通知VMC,当前商品售价
        表示设置单价的方式;Type = 0:为按商品ID 发送单价,可以变长发送,商品种类最大不超过80 个;Type = 1: 为按货道号发送,固定发送80 个货道的单价信息<param name="sp_price">商品售价bool SALEPRICE_IND( sp_price)
        {
            List< };
            sendData.Add(device);
            sendData.Add(type);
            sendData.AddRange(sp_price.ConvertAll<0x8E,1)">#region PAYOUT_IND PC指示VMC出币
         PC指示VMC出币
        出币设备<param name="value">本次出币总金额出币类型 无需理解type 的含义,只需要在出币完成后的PAYOUT_RPT 中将该type 值回传给PC 即可public PayoutRpt PAYOUT_IND(PayoutType device,1)">int value,1)"> type)
        {
            List<0x89 };
            sendData.Add(()device);
            sendData.AddRange(CommonUtil.Int2ByteArray(value,1)">));
            sendData.Add(type);
            m_CommandList.Add(0x89,1)"> PayoutRpt(receiveData);
                }
            }
            #region COST_IND PC扣款指示
         PC扣款指示
        device=0,从用户投币总额中扣款;优先从用户非暂存金额中扣除(纸币尽量滞后压钞),参见《现金扣款顺序》扣款金额VMC 不用理解type 的含义,只需上报对应的COST_RPT 时回传即可public CostRpt COST_IND(0x8B };
            sendData.Add(device);
            sendData.AddRange(CommonUtil.Int2ByteArray(value,1)">0x8B,1)"> CostRpt(receiveData);
                }
            }
            #region GET_HUODAO PC通知VMC上报HUODAO_RPT
         PC通知VMC上报HUODAO_RPT
        箱柜号public HuoDaoRpt GET_HUODAO( device)
        {
            List<0x8A };
            sendData.Add(device);
            m_CommandList.Add( HuoDaoRpt(receiveData);
            }
            #region SET_HUODAO PC发送配置货道信息
         PC发送配置货道信息
        <param name="Cabinet"><param name="hd_no">货道逻辑编号,十进制<param name="Hd_id">商品ID号<param name="Hd_count">货道剩余量<param name="Hd_price">货道单价<param name="Reserved">保留字段VMC忽略此字段,PC最好将此字段置为0bool SET_HUODAO(byte Cabinet,1)">int hd_no,1)">int Hd_id,1)">int Hd_count,1)">int Hd_price,1)">int Reserved = )
        {
            List<0x93 };
            sendData.Add(Cabinet);
            sendData.Add(()hd_no);
            sendData.Add(()Hd_id);
            sendData.Add(()Hd_count);
            sendData.AddRange(CommonUtil.Int2ByteArray(Hd_price,1)">));
            sendData.AddRange(CommonUtil.Int2ByteArray(Reserved,1)">0x93,1)">#region 开启纸硬币器
         现金收银模组(纸币器、硬币器)开关
        <param name="open">true:开,false:关bool CtrlCoinPaper(bool open)
        {
             (open)
            {
                2,1)"> });
            }
            
            {
                 });
            }
        }
        #region 找零
         找零
         与手工拨弄物理找零开关相同
         MakeChange()
        {
            6,1)"> });
        }
        #region 获取硬币器信息
         获取硬币器信息
         InfoRpt_17 GetCoinInfo()
        {
            new InfoRpt_17(GET_INFO());
        }
        #region 获取纸币器信息
         获取纸币器信息
         InfoRpt_16 GetPaperInfo()
        {
            new InfoRpt_16(GET_INFO(#region 获取现金投币报告
         获取现金投币报告
         PayinRpt GetPayinRpt()
        {
            byte[] receiveData = Receive(0x06,1)"> PayinRpt(receiveData);
            }
            #region 获取用户投币余额
         获取用户投币余额
         InfoRpt_3 GetRemaiderAmount()
        {
            0x11,1)">0x003 InfoRpt_3(receiveData);
            }
            

    }
}
View Code

ReceiveDataCollection类和ReceiveData类:

 System.Text;

 MachineJPDll.Models
{
     从串口接收到的数据(数据已通过验证)
     ReceiveData
    {
         从串口接收到的数据(数据已通过验证)
        byte[] Data { get; set; }
         添加到集合ReceiveDataCollection的时间
        public DateTime AddTime {  消息类型
        byte Type {  消息子类型
        byte Subtype { ; }

        <param name="data">从串口接收到的数据(数据已通过验证)<param name="addTime">添加到集合ReceiveDataCollection的时间public ReceiveData([] data,DateTime addTime)
        {
            this.Type = type;
            this.Subtype = subtype;
            this.Data = data;
            this.AddTime = addTime;
        }
    }
}
View Code

 从串口接收到的数据集合(数据已通过验证)
     ReceiveDataCollection
    {
         从串口接收到的数据集合(数据已通过验证)
        private List<ReceiveData> m_ReceiveDataList = new List<ReceiveData> 数据过期时间
        int m_Timeout = ;
        static object _lock = ();

         添加到集合
        void Add([] data)
        {
            lock (_lock)
            {
                ReceiveData receiveData =  ReceiveData(type,subtype,data,DateTime.Now);
                m_ReceiveDataList.Add(receiveData);
                int i = m_ReceiveDataList.Count - 1; i >= 0; i--if (DateTime.Now.Subtract(m_ReceiveDataList[i].AddTime).TotalMinutes > m_Timeout)
                    {
                        m_ReceiveDataList.RemoveAt(i);
                    }
                }
            }
        }

         从集合中获取串口接收到的数据(数据已通过验证)
        byte[] Get(0; i < m_ReceiveDataList.Count; i++if (m_ReceiveDataList[i].Type == type && m_ReceiveDataList[i].Subtype == subtype)
                    {
                        receiveData = m_ReceiveDataList[i];
                        m_ReceiveDataList.RemoveAt(i);
                         receiveData.Data;
                    }
                }
                ;
            }
        }

         type)
        {
            if (m_ReceiveDataList[i].Type == type)
                    {
                        receiveData =;
            }
        }
    }
}
View Code

Models:

StatusRpt类:

 MachineJPDll;
 VMC状态报告
     StatusRpt
    {
         从串口读取的通过验证的数据
        [] m_data;

         VMC状态报告
        从串口读取的通过验证的数据public StatusRpt([] data)
        {
            m_data = data;
        }

        override  ToString()
        {
            StringBuilder sb =  StringBuilder();
            sb.AppendFormat(出货检测设备状态:{0}\r\n纸币器状态:{0}\r\n硬币器状态:{0}\r\nVMC状态:{0}\r\n展示位状态:{0} {1} {2} {3}\r\n",pos_st[0].ToString(),1)">1].ToString(),1)">2].ToString(),1)">].ToString());
            sb.AppendFormat(机器中可用的找零量总金额(包括硬币和纸币):{0}\r\n货仓1货仓2货仓3货仓4温度:{0} {1} {2} {3}\r\n货仓状态设置值:{0} {1} {2} {3}\r\n].ToString());
            if (this.自动退币 == 255)
            {
                sb.AppendFormat(自动退币时间:永不自动退币\r\n);
            }
            
            {
                sb.AppendFormat(自动退币时间:{0}\r\n自动退币.ToString());
            }
            sb.AppendFormat(找零余量(1#--6#):{0} {1} {2} {3} {4} {5}\r\nthis.找零余量1,1)">this.找零余量2,1)">this.找零余量3,1)">this.找零余量4,1)">this.找零余量5,1)">this.找零余量6);

             sb.ToString();
        }

         出货检测设备状态
         CheckSt check_st
        {
            getbyte val = m_data[5];
                return (CheckSt)CommonUtil.GetFromByte(val,1)">0,1)"> 纸币器状态
         DeviceSt bv_st
        {
            return (DeviceSt)CommonUtil.GetFromByte(val,1)"> 硬币器状态
         DeviceSt cc_st
        {
            4,1)"> VMC状态
         VmcSt vmc_st
        {
            return (VmcSt)CommonUtil.GetFromByte(val,1)"> 展示位状态
        public List<DeviceSt> pos_st
        {
            
            {
                List<DeviceSt> deviceStList = new List<DeviceSt>();

                60; i < 4; i++)
                {
                    DeviceSt deviceSt = (DeviceSt)CommonUtil.GetFromByte(val,i * );
                    deviceStList.Add(deviceSt);
                }

                 deviceStList;
            }
        }

         机器中,可用的找零量总金额(包括硬币和纸币)
         change
        {
            return CommonUtil.ByteArray2Int(m_data,1)">7,1)"> 货仓1 温度,8 位有符号数,该温度通过货仓内传感器获取,单位:℃
         TemSub tem1
        {
            new TemSub(m_data[9]);
            }
        }

         货仓2 温度,8 位有符号数,该温度通过货仓内传感器获取,单位:℃
         TemSub tem2
        {
            10 货仓3 温度,8 位有符号数,该温度通过货仓内传感器获取,单位:℃
         TemSub tem3
        {
            11 货仓4 温度,8 位有符号数,该温度通过货仓内传感器获取,单位:℃
         TemSub tem4
        {
            12 货仓状态设置值,共支持4 个货仓
        public List<TemSt> tem_st
        {
            
            {
                List<TemSt> temStList = new List<TemSt>();
                )
                {
                    TemSt temSt = (TemSt)CommonUtil.GetFromByte(m_data[13],1)">);
                    temStList.Add(temSt);
                }
                 temStList;
            }
        }

         自动退币时间。
         0:表示商品出货后,立即自动退币
         255:表示永不自动退币
         1-254:表示商品出货后,自动退币时间(单位:秒)
         自动退币
        {
            return m_data[14];
            }
        }

         找零余量“找零量1#”…“找零量6#”,分别对应硬币器信息INFO_RPT.type=17 的“找零
         1#”…“找零6#”中每种钱币的找零数量 * 找零量最大为255,超过255 时上报为255;
         * 找零量单位为“个”,代表可找零硬币的个数。
         找零余量1
        {
            15 找零余量2
        {
             找零余量3
        {
             找零余量4
        {
            18 找零余量5
        {
            19 找零余量6
        {
            20];
            }
        }

    }
}
View Code

 

GitHub地址:https://github.com/0611163/Machine.git

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐