欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

通过C#实现自动售货机接口

程序员文章站 2023-11-16 23:25:04
下面分几部分介绍c#实现自动售货机接口的方法,代码写的非常详细,不懂的地方有注释可以参考下。 machinejp类: 第1部分:串口初始化,串口数据读写 us...

下面分几部分介绍c#实现自动售货机接口的方法,代码写的非常详细,不懂的地方有注释可以参考下。

machinejp类:

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

using system;
using system.collections.generic;
using system.io.ports;
using system.linq;
using system.text;
using system.threading;
using system.threading.tasks;
using system.windows.forms;
using machinejpdll.models;
using machinejpdll.utils;

namespace machinejpdll
{
  /// <summary>
  /// 售货机接口(接口)
  /// </summary>
  public partial class machinejp
  {
    #region 变量
    /// <summary>
    /// 串口资源
    /// </summary>
    private serialport m_serialport = null;
    /// <summary>
    /// 待发送给串口的命令列表
    /// </summary>
    private list<cmd> m_commandlist = new list<cmd>();
    /// <summary>
    /// 等待ack_rpt或nak_rpt的pc端向vmc端发送的消息列表
    /// </summary>
    private list<mt> m_waitresultmtlist = new list<mt>();
    /// <summary>
    /// 从串口接收的数据集合(数据已通过验证)
    /// </summary>
    private receivedatacollection m_receivedatacollection = new receivedatacollection();
    #endregion

    #region 构造函数与析构函数
    /// <summary>
    /// 售货机接口(接口)
    /// </summary>
    public machinejp()
    {

    }

    ~machinejp()
    {
      if (m_serialport != null)
      {
        m_serialport.close();
        m_serialport.dispose();
        m_serialport = null;
      }
    }
    #endregion

    #region 读取串口数据
    /// <summary>
    /// 读取串口数据
    /// </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 = new byte[m_serialport.bytestoread];
      m_serialport.read(recdata, 0, recdata.length);
      reclist.addrange(recdata);
      int length = recdata[1] + 2; //报文数据总长度
      while (reclist.count < length)
      {
        if (m_serialport.bytestoread > 0)
        {
          recdata = new byte[m_serialport.bytestoread];
          m_serialport.read(recdata, 0, recdata.length);
          reclist.addrange(recdata);
        }
        thread.sleep(1);
      }

      return reclist.toarray();
    }
    #endregion

    #region 向串口发送数据
    /// <summary>
    /// 向串口发送数据
    /// </summary>
    /// <param name="cmd">待发送的命令</param>
    /// <param name="sn">序列号</param>
    private void writeport(cmd cmd, byte sn)
    {
      //发送数据
      list<byte> senddata = cmd.data;
      senddata[1] = (byte)senddata.count;
      senddata[2] = sn;
      byte[] checkcode = commonutil.calcheckcode(senddata, senddata.count);
      senddata.addrange(checkcode);
      if (cmd.mt != null)
      {
        m_waitresultmtlist.add(cmd.mt);
      }
      m_serialport.write(senddata.toarray(), 0, senddata.count);
      loghelper.log(logmsgtype.info, true, senddata.toarray());
    }
    #endregion

    #region 发送ack消息
    /// <summary>
    /// 发送ack消息
    /// </summary>
    /// <param name="sn">序列号</param>
    private void sendack(byte sn)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x40, 0x80 };
      writeport(new cmd(senddata), sn);
    }
    #endregion

    #region init 初始化
    /// <summary>
    /// 初始化
    /// </summary>
    /// <param name="com">串口号(例:com1)</param>
    public void init(string com)
    {
      if (m_serialport == null)
      {
        m_serialport = new serialport(com, 9600, parity.none, 8, stopbits.one);
        m_serialport.readbuffersize = 1024;
        m_serialport.writebuffersize = 1024;
        m_serialport.datareceived += new serialdatareceivedeventhandler(serialport_datareceived);
      }

      if (!m_serialport.isopen)
      {
        m_serialport.open();
      }

      get_setup();
      control_ind(0x13, new byte[] { 0x00 }); //初始化完成标志
      get_status();

      setdecimalplaces(2); //设置小数点位数
    }
    #endregion

    #region close 关闭连接
    /// <summary>
    /// 关闭连接
    /// </summary>
    public void close()
    {
      m_serialport.close();
    }
    #endregion

    #region 接收串口数据
    /// <summary>
    /// 接收串口数据
    /// </summary>
    /// <param name="type">消息类型</param>
    /// <param name="subtype">消息子类型</param>
    public byte[] receive(byte type, byte subtype)
    {
      return m_receivedatacollection.get(type, subtype);
    }

    /// <summary>
    /// 接收串口数据
    /// </summary>
    /// <param name="type">消息类型</param>
    /// <param name="subtype">消息子类型</param>
    public byte[] waitreceive(byte type, byte subtype)
    {
      datetime time = datetime.now;
      while (true)
      {
        byte[] receivedata = m_receivedatacollection.get(type, subtype);
        if (receivedata != null) return receivedata;

        if (datetime.now.subtract(time).totalminutes > 3) return null;

        thread.sleep(50);
      }
    }

    /// <summary>
    /// 接收串口数据
    /// </summary>
    /// <param name="type">消息类型</param>
    public byte[] waitreceive(byte type)
    {
      datetime time = datetime.now;
      while (true)
      {
        byte[] receivedata = m_receivedatacollection.get(type);
        if (receivedata != null) return receivedata;

        if (datetime.now.subtract(time).totalminutes > 3) return null;

        thread.sleep(50);
      }
    }
    #endregion

    #region 判断消息是否发送成功
    /// <summary>
    /// 判断消息是否发送成功
    /// </summary>
    public bool sendsuccess(byte type, byte subtype)
    {
      datetime time = datetime.now;
      while (true)
      {
        if (datetime.now.subtract(time).totalminutes > 3)
        {
          return false;
        }
        byte[] ack = m_receivedatacollection.get(type, subtype);
        byte[] nak = m_receivedatacollection.get(type, subtype);
        if (ack != null) return true;
        if (nak != null) return false;

        thread.sleep(1);
      }
    }
    #endregion

  }
}

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

 

using system;
using system.collections.generic;
using system.io.ports;
using system.linq;
using system.text;
using machinejpdll.models;
using machinejpdll.utils;

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

namespace machinejpdll
{
  partial class machinejp
  {
    #region serialport_datareceived
    /// <summary>
    /// 数据接收事件的方法
    /// </summary>
    public void serialport_datareceived(object obj, serialdatareceivedeventargs args)
    {
      byte[] receivedata = readport();

      if (commonutil.validreceivedata(receivedata)) //只处理验证正确的数据,不正确的数据抛弃不处理
      {
        loghelper.log(logmsgtype.info, false, receivedata);
        byte sn = commonutil.getsn(receivedata);
        mt mt = new mt(receivedata);

        #region 轮询(poll)
        if (mt.type == 0x03)
        {
          if (m_commandlist.count > 0)
          {
            writeport(m_commandlist[0], sn);
            m_commandlist.removeat(0);
          }
          else
          {
            //发送ack消息
            sendack(sn);
          }
        }
        #endregion

        #region 发送ack消息
        if (commonutil.needack(receivedata))
        {
          sendack(sn); //发送ack消息
        }
        #endregion

        #region vmc系统参数
        if (mt.type == 0x05)
        {
          m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
        }
        #endregion

        #region ack_rpt或nak_rpt
        if (mt.type == 0x01 //ack_rpt
          || mt.type == 0x02) //nak_rpt
        {
          if (m_waitresultmtlist.count > 0)
          {
            m_receivedatacollection.add(m_waitresultmtlist[0].type, m_waitresultmtlist[0].subtype, receivedata);
            m_waitresultmtlist.removeat(0);
          }
        }
        #endregion

        #region info_rpt 数据报告
        if (mt.type == 0x11)
        {
          #region 纸币器信息
          if (mt.subtype == 16)
          {
            m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
          }
          #endregion

          #region 硬币器信息
          if (mt.subtype == 17)
          {
            m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
          }
          #endregion

          #region 用户投币余额
          if (mt.subtype == 3)
          {
            m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
          }
          #endregion
        }
        #endregion

        #region vendout_rpt 出货报告
        if (mt.type == 0x08)
        {
          m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
        }
        #endregion

        #region status_rpt vmc整机状态报告
        if (mt.type == 0x0d)
        {
          m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
        }
        #endregion

        #region saleprice_ind 设置当前商品售价
        if (mt.type == 0x8e)
        {
          m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
        }
        #endregion

        #region payin_rpt vmc发送现金投币报告给pc
        if (mt.type == 0x06)
        {
          m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
        }
        #endregion

        #region payout_rpt 出币报告
        if (mt.type == 0x07)
        {
          m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
        }
        #endregion

        #region cost_rpt vmc扣款报告
        if (mt.type == 0x10)
        {
          m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
        }
        #endregion

        #region action_rpt 售货机行为报告
        if (mt.type == 0x0b)
        {
          m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
        }
        #endregion

        #region huodao_rpt vmc货道报告
        if (mt.type == 0x0e)
        {
          m_receivedatacollection.add(mt.type, mt.subtype, receivedata);
        }
        #endregion
      }
      else //接收到的数据没有验证通过
      {
        loghelper.logexception(logmsgtype.error, false, "数据异常", receivedata);
      }
    }
    #endregion

  }
}

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

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading;
using machinejpdll.enums;
using machinejpdll.models;
using machinejpdll.utils;

/*
 * pc->vmc数据的发送(并非直接发送,只是添加到发送列表)
 */

namespace machinejpdll
{
  partial class machinejp
  {
    #region get_setup
    /// <summary>
    /// pc通知vmc发送vmc_setup
    /// </summary>
    public vmcsetup get_setup()
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x40, 0x90 };
      m_commandlist.add(new cmd(senddata));

      byte[] receivedata = waitreceive(0x05);
      if (receivedata != null)
      {
        return new vmcsetup(receivedata);
      }
      return null;
    }
    #endregion

    #region control_ind pc控制售货机完成对应的动作
    /// <summary>
    /// pc控制vmc
    /// </summary>
    public bool control_ind(byte subtype, byte[] value)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x41, 0x85 };
      senddata.add(subtype);
      if (value != null && value.length > 0)
      {
        senddata.addrange(value);
      }
      m_commandlist.add(new cmd(senddata, new mt(senddata)));

      return sendsuccess(0x85, subtype);
    }
    #endregion

    #region 设置小数点位数
    /// <summary>
    /// 设置小数点位数
    /// 用于pc 通知vmc,双方的金额数据比例系数关系,pc 每次启动时,都会给
    /// vmc 下发一次type=18 的消息,vmc 需要自己永久保存该数据,直到被pc 再
    /// 次更新。
    /// 取值范围:0、1、2 分别表示以 元、 角 、分 为单位
    /// </summary>
    public bool setdecimalplaces(int data)
    {
      return control_ind(18, new byte[] { (byte)data });
    }
    #endregion

    #region get_status pc通知vmc发送status_rpt
    /// <summary>
    /// pc通知vmc发送status_rpt
    /// </summary>
    public statusrpt get_status()
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x40, 0x86 };
      m_commandlist.add(new cmd(senddata));

      byte[] receivedata = waitreceive(0x0d);
      if (receivedata != null)
      {
        return new statusrpt(receivedata);
      }
      return null;
    }
    #endregion

    #region get_info pc通知vmc发送info_rpt
    /// <summary>
    /// pc通知vmc发送info_rpt
    /// </summary>
    public byte[] get_info(byte subtype)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x40, 0x8c };
      senddata.add(subtype);
      m_commandlist.add(new cmd(senddata));

      return waitreceive(0x11);
    }
    #endregion

    #region vendout_ind 出货
    /// <summary>
    /// pc出货指示
    /// </summary>
    /// <param name="device">售货机的箱体号 例如柜1 为 0x01 以此类推</param>
    /// <param name="method">method =1:vmc 通过商品id 指示出货,如果商品id 不存在,回复nak_rpt method =2:vmc 通过货道id 指示vmc 出货,如果货道id 不存在,回复nak_rpt</param>
    /// <param name="sp_id_hd_id">sp_id:通过商品id 指示vmc 出货 hd_id:通过货道id 指示vmc 出货</param>
    /// <param name="type">如果type=0,cost 代表本次出货扣款金额 如果type 不为0,则cost 必须为0</param>
    /// <param name="cost">cost 代表本次出货扣款金额</param>
    public vendoutrpt vendout_ind(byte device, byte method, byte sp_id_hd_id, byte type, int cost)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x41, 0x83 };
      senddata.addrange(new byte[] { device, method, sp_id_hd_id, type });
      senddata.addrange(commonutil.int2bytearray(cost, 2));
      m_commandlist.add(new cmd(senddata, new mt(senddata)));

      if (sendsuccess(0x83, 0x00))
      {
        byte[] receivedata = waitreceive(0x08);
        if (receivedata != null)
        {
          return new vendoutrpt(receivedata);
        }
      }
      return null;
    }
    #endregion

    #region huodao_set_ind 设置货道商品数量
    /// <summary>
    /// pc通知vmc,当前货道对应商品的数量等信息
    /// </summary>
    /// <param name="device">表示箱柜号</param>
    /// <param name="huodao">zyxxxxxx “z”固定填0 “y”固定填0 “xxxxxx”,表示商品余量,如果商品余量大于63,则统一为63</param>
    public bool huodao_set_ind(byte device, list<int> huodao)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x41, 0x8f };
      senddata.add(device);
      for (int i = 0; i < huodao.count; i++)
      {
        if (huodao[i] > 63)
        {
          huodao[i] = 63;
        }
      }
      senddata.addrange(huodao.convertall<byte>(a => (byte)a));
      m_commandlist.add(new cmd(senddata, new mt(senddata)));

      return sendsuccess(0x8f, 0x00);
    }
    #endregion

    #region saleprice_ind 设置当前商品售价
    /// <summary>
    /// pc通知vmc,当前商品售价
    /// </summary>
    /// <param name="device">表示箱柜号</param>
    /// <param name="type">表示设置单价的方式;type = 0:为按商品id 发送单价,可以变长发送,商品种类最大不超过80 个;type = 1: 为按货道号发送,固定发送80 个货道的单价信息</param>
    /// <param name="sp_price">商品售价</param>
    public bool saleprice_ind(byte device, byte type, list<int> sp_price)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x41, 0x8e };
      senddata.add(device);
      senddata.add(type);
      senddata.addrange(sp_price.convertall<byte>(a => (byte)a));
      m_commandlist.add(new cmd(senddata, new mt(senddata)));

      return sendsuccess(0x8e, 0x00);
    }
    #endregion

    #region payout_ind pc指示vmc出币
    /// <summary>
    /// pc指示vmc出币
    /// </summary>
    /// <param name="device">出币设备</param>
    /// <param name="value">本次出币总金额</param>
    /// <param name="type">出币类型 无需理解type 的含义,只需要在出币完成后的payout_rpt 中将该type 值回传给pc 即可</param>
    public payoutrpt payout_ind(payouttype device, int value, byte type)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x41, 0x89 };
      senddata.add((byte)device);
      senddata.addrange(commonutil.int2bytearray(value, 2));
      senddata.add(type);
      m_commandlist.add(new cmd(senddata, new mt(senddata)));

      if (sendsuccess(0x89, 0x00))
      {
        byte[] receivedata = waitreceive(0x07);
        if (receivedata != null)
        {
          return new payoutrpt(receivedata);
        }
      }
      return null;
    }
    #endregion

    #region cost_ind pc扣款指示
    /// <summary>
    /// pc扣款指示
    /// </summary>
    /// <param name="device">device=0,从用户投币总额中扣款;优先从用户非暂存金额中扣除(纸币尽量滞后压钞),参见《现金扣款顺序》</param>
    /// <param name="value">扣款金额</param>
    /// <param name="type">vmc 不用理解type 的含义,只需上报对应的cost_rpt 时回传即可</param>
    public costrpt cost_ind(byte device, int value, byte type)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x41, 0x8b };
      senddata.add(device);
      senddata.addrange(commonutil.int2bytearray(value, 2));
      senddata.add(type);
      m_commandlist.add(new cmd(senddata, new mt(senddata)));

      if (sendsuccess(0x8b, 0x00))
      {
        byte[] receivedata = waitreceive(0x10);
        if (receivedata != null)
        {
          return new costrpt(receivedata);
        }
      }
      return null;
    }
    #endregion

    #region get_huodao pc通知vmc上报huodao_rpt
    /// <summary>
    /// pc通知vmc上报huodao_rpt
    /// </summary>
    /// <param name="device">箱柜号</param>
    public huodaorpt get_huodao(byte device)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x40, 0x8a };
      senddata.add(device);
      m_commandlist.add(new cmd(senddata));

      byte[] receivedata = waitreceive(0x0e);
      if (receivedata != null)
      {
        return new huodaorpt(receivedata);
      }
      return null;
    }
    #endregion

    #region set_huodao pc发送配置货道信息
    /// <summary>
    /// pc发送配置货道信息
    /// </summary>
    /// <param name="cabinet">箱柜号</param>
    /// <param name="hd_no">货道逻辑编号,十进制</param>
    /// <param name="hd_id">商品id号</param>
    /// <param name="hd_count">货道剩余量</param>
    /// <param name="hd_price">货道单价</param>
    /// <param name="reserved">保留字段vmc忽略此字段,pc最好将此字段置为0</param>
    public bool set_huodao(byte cabinet, int hd_no, int hd_id, int hd_count, int hd_price, int reserved = 0)
    {
      list<byte> senddata = new list<byte>() { 0xe5, 0x00, 0x00, 0x41, 0x93 };
      senddata.add(cabinet);
      senddata.add((byte)hd_no);
      senddata.add((byte)hd_id);
      senddata.add((byte)hd_count);
      senddata.addrange(commonutil.int2bytearray(hd_price, 2));
      senddata.addrange(commonutil.int2bytearray(reserved, 2));
      m_commandlist.add(new cmd(senddata, new mt(senddata)));

      return sendsuccess(0x93, 0x00);
    }
    #endregion

    #region 开启纸硬币器
    /// <summary>
    /// 现金收银模组(纸币器、硬币器)开关
    /// </summary>
    /// <param name="open">true:开,false:关</param>
    public bool ctrlcoinpaper(bool open)
    {
      if (open)
      {
        return control_ind(2, new byte[] { 1 });
      }
      else
      {
        return control_ind(2, new byte[] { 0 });
      }
    }
    #endregion

    #region 找零
    /// <summary>
    /// 找零
    /// 与手工拨弄物理找零开关相同
    /// </summary>
    public bool makechange()
    {
      return control_ind(6, new byte[] { 0 });
    }
    #endregion

    #region 获取硬币器信息
    /// <summary>
    /// 获取硬币器信息
    /// </summary>
    public inforpt_17 getcoininfo()
    {
      return new inforpt_17(get_info(17));
    }
    #endregion

    #region 获取纸币器信息
    /// <summary>
    /// 获取纸币器信息
    /// </summary>
    public inforpt_16 getpaperinfo()
    {
      return new inforpt_16(get_info(16));
    }
    #endregion

    #region 获取现金投币报告
    /// <summary>
    /// 获取现金投币报告
    /// </summary>
    public payinrpt getpayinrpt()
    {
      byte[] receivedata = receive(0x06, 0x00);
      if (receivedata != null)
      {
        return new payinrpt(receivedata);
      }
      return null;
    }
    #endregion

    #region 获取用户投币余额
    /// <summary>
    /// 获取用户投币余额
    /// </summary>
    public inforpt_3 getremaideramount()
    {
      byte[] receivedata = waitreceive(0x11, 0x003);
      if (receivedata != null)
      {
        return new inforpt_3(receivedata);
      }
      return null;
    }
    #endregion

  }
}

receivedatacollection类和receivedata类: 

 

using system;
using system.collections.generic;
using system.linq;
using system.text;

namespace machinejpdll.models
{
  /// <summary>
  /// 从串口接收到的数据(数据已通过验证)
  /// </summary>
  public class receivedata
  {
    /// <summary>
    /// 从串口接收到的数据(数据已通过验证)
    /// </summary>
    public byte[] data { get; set; }
    /// <summary>
    /// 添加到集合receivedatacollection的时间
    /// </summary>
    public datetime addtime { get; set; }
    /// <summary>
    /// 消息类型
    /// </summary>
    public byte type { get; set; }
    /// <summary>
    /// 消息子类型
    /// </summary>
    public byte subtype { get; set; }

    /// <summary>
    /// 从串口接收到的数据(数据已通过验证)
    /// </summary>
    /// <param name="type">消息类型</param>
    /// <param name="subtype">消息子类型</param>
    /// <param name="data">从串口接收到的数据(数据已通过验证)</param>
    /// <param name="addtime">添加到集合receivedatacollection的时间</param>
    public receivedata(byte type, byte subtype, byte[] data, datetime addtime)
    {
      this.type = type;
      this.subtype = subtype;
      this.data = data;
      this.addtime = addtime;
    }
  }
}
using system;
using system.collections.generic;
using system.linq;
using system.text;

namespace machinejpdll.models
{
  /// <summary>
  /// 从串口接收到的数据集合(数据已通过验证)
  /// </summary>
  public class receivedatacollection
  {
    /// <summary>
    /// 从串口接收到的数据集合(数据已通过验证)
    /// </summary>
    private list<receivedata> m_receivedatalist = new list<receivedata>();
    /// <summary>
    /// 数据过期时间
    /// </summary>
    private int m_timeout = 3;
    private static object _lock = new object();

    /// <summary>
    /// 添加到集合
    /// </summary>
    /// <param name="type">消息类型</param>
    /// <param name="subtype">消息子类型</param>
    /// <param name="data">从串口接收到的数据(数据已通过验证)</param>
    public void add(byte type, byte subtype, byte[] data)
    {
      lock (_lock)
      {
        receivedata receivedata = new receivedata(type, subtype, data, datetime.now);
        m_receivedatalist.add(receivedata);
        for (int i = m_receivedatalist.count - 1; i >= 0; i--)
        {
          if (datetime.now.subtract(m_receivedatalist[i].addtime).totalminutes > m_timeout)
          {
            m_receivedatalist.removeat(i);
          }
        }
      }
    }

    /// <summary>
    /// 从集合中获取串口接收到的数据(数据已通过验证)
    /// </summary>
    /// <param name="type">消息类型</param>
    /// <param name="subtype">消息子类型</param>
    /// <returns>从串口接收到的数据(数据已通过验证)</returns>
    public byte[] get(byte type, byte subtype)
    {
      lock (_lock)
      {
        receivedata receivedata = null;
        for (int i = 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);
            return receivedata.data;
          }
        }
        return null;
      }
    }

    /// <summary>
    /// 从集合中获取串口接收到的数据(数据已通过验证)
    /// </summary>
    /// <param name="type">消息类型</param>
    /// <returns>从串口接收到的数据(数据已通过验证)</returns>
    public byte[] get(byte type)
    {
      lock (_lock)
      {
        receivedata receivedata = null;
        for (int i = 0; i < m_receivedatalist.count; i++)
        {
          if (m_receivedatalist[i].type == type)
          {
            receivedata = m_receivedatalist[i];
            m_receivedatalist.removeat(i);
            return receivedata.data;
          }
        }
        return null;
      }
    }
  }
}

models:

statusrpt类:

using system;
using system.collections.generic;
using system.linq;
using system.text;
using machinejpdll;
using machinejpdll.enums;
using machinejpdll.utils;

namespace machinejpdll.models
{
  /// <summary>
  /// vmc状态报告
  /// </summary>
  public class statusrpt
  {
    /// <summary>
    /// 从串口读取的通过验证的数据
    /// </summary>
    private byte[] m_data;

    /// <summary>
    /// vmc状态报告
    /// </summary>
    /// <param name="data">从串口读取的通过验证的数据</param>
    public statusrpt(byte[] data)
    {
      m_data = data;
    }

    public override string tostring()
    {
      stringbuilder sb = new stringbuilder();
      sb.appendformat("出货检测设备状态:{0}\r\n", check_st.tostring());
      sb.appendformat("纸币器状态:{0}\r\n", bv_st.tostring());
      sb.appendformat("硬币器状态:{0}\r\n", cc_st.tostring());
      sb.appendformat("vmc状态:{0}\r\n", vmc_st.tostring());
      sb.appendformat("展示位状态:{0} {1} {2} {3}\r\n", pos_st[0].tostring(), pos_st[1].tostring(), pos_st[2].tostring(), pos_st[3].tostring());
      sb.appendformat("机器中可用的找零量总金额(包括硬币和纸币):{0}\r\n", change.tostring());
      sb.appendformat("货仓1货仓2货仓3货仓4温度:{0} {1} {2} {3}\r\n", tem1.tostring(), tem2.tostring(), tem3.tostring(), tem4.tostring());
      sb.appendformat("货仓状态设置值:{0} {1} {2} {3}\r\n", tem_st[0].tostring(), tem_st[1].tostring(), tem_st[2].tostring(), tem_st[3].tostring());
      if (this.自动退币 == 255)
      {
        sb.appendformat("自动退币时间:永不自动退币\r\n");
      }
      else
      {
        sb.appendformat("自动退币时间:{0}\r\n", 自动退币.tostring());
      }
      sb.appendformat("找零余量(1#--6#):{0} {1} {2} {3} {4} {5}\r\n", this.找零余量1, this.找零余量2, this.找零余量3, this.找零余量4, this.找零余量5, this.找零余量6);

      return sb.tostring();
    }

    /// <summary>
    /// 出货检测设备状态
    /// </summary>
    public checkst check_st
    {
      get
      {
        byte val = m_data[5];
        return (checkst)commonutil.getfrombyte(val, 0, 2);
      }
    }

    /// <summary>
    /// 纸币器状态
    /// </summary>
    public devicest bv_st
    {
      get
      {
        byte val = m_data[5];
        return (devicest)commonutil.getfrombyte(val, 2, 2);
      }
    }

    /// <summary>
    /// 硬币器状态
    /// </summary>
    public devicest cc_st
    {
      get
      {
        byte val = m_data[5];
        return (devicest)commonutil.getfrombyte(val, 4, 2);
      }
    }

    /// <summary>
    /// vmc状态
    /// </summary>
    public vmcst vmc_st
    {
      get
      {
        byte val = m_data[5];
        return (vmcst)commonutil.getfrombyte(val, 6, 2);
      }
    }

    /// <summary>
    /// 展示位状态
    /// </summary>
    public list<devicest> pos_st
    {
      get
      {
        list<devicest> devicestlist = new list<devicest>();

        byte val = m_data[6];
        for (int i = 0; i < 4; i++)
        {
          devicest devicest = (devicest)commonutil.getfrombyte(val, i * 2, 2);
          devicestlist.add(devicest);
        }

        return devicestlist;
      }
    }

    /// <summary>
    /// 机器中,可用的找零量总金额(包括硬币和纸币)
    /// </summary>
    public int change
    {
      get
      {
        return commonutil.bytearray2int(m_data, 7, 2);
      }
    }

    /// <summary>
    /// 货仓1 温度,8 位有符号数,该温度通过货仓内传感器获取,单位:℃
    /// </summary>
    public temsub tem1
    {
      get
      {
        return new temsub(m_data[9]);
      }
    }

    /// <summary>
    /// 货仓2 温度,8 位有符号数,该温度通过货仓内传感器获取,单位:℃
    /// </summary>
    public temsub tem2
    {
      get
      {
        return new temsub(m_data[10]);
      }
    }

    /// <summary>
    /// 货仓3 温度,8 位有符号数,该温度通过货仓内传感器获取,单位:℃
    /// </summary>
    public temsub tem3
    {
      get
      {
        return new temsub(m_data[11]);
      }
    }

    /// <summary>
    /// 货仓4 温度,8 位有符号数,该温度通过货仓内传感器获取,单位:℃
    /// </summary>
    public temsub tem4
    {
      get
      {
        return new temsub(m_data[12]);
      }
    }

    /// <summary>
    /// 货仓状态设置值,共支持4 个货仓
    /// </summary>
    public list<temst> tem_st
    {
      get
      {
        list<temst> temstlist = new list<temst>();
        for (int i = 0; i < 4; i++)
        {
          temst temst = (temst)commonutil.getfrombyte(m_data[13], i * 2, 2);
          temstlist.add(temst);
        }
        return temstlist;
      }
    }

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

    /// <summary>
    /// 找零余量“找零量1#”…“找零量6#”,分别对应硬币器信息info_rpt.type=17 的“找零
    /// 1#”…“找零6#”中每种钱币的找零数量;
    /// * 找零量最大为255,超过255 时上报为255;
    /// * 找零量单位为“个”,代表可找零硬币的个数。
    /// </summary>
    public int 找零余量1
    {
      get
      {
        return m_data[15];
      }
    }

    /// <summary>
    /// 找零余量“找零量1#”…“找零量6#”,分别对应硬币器信息info_rpt.type=17 的“找零
    /// 1#”…“找零6#”中每种钱币的找零数量;
    /// * 找零量最大为255,超过255 时上报为255;
    /// * 找零量单位为“个”,代表可找零硬币的个数。
    /// </summary>
    public int 找零余量2
    {
      get
      {
        return m_data[16];
      }
    }

    /// <summary>
    /// 找零余量“找零量1#”…“找零量6#”,分别对应硬币器信息info_rpt.type=17 的“找零
    /// 1#”…“找零6#”中每种钱币的找零数量;
    /// * 找零量最大为255,超过255 时上报为255;
    /// * 找零量单位为“个”,代表可找零硬币的个数。
    /// </summary>
    public int 找零余量3
    {
      get
      {
        return m_data[17];
      }
    }

    /// <summary>
    /// 找零余量“找零量1#”…“找零量6#”,分别对应硬币器信息info_rpt.type=17 的“找零
    /// 1#”…“找零6#”中每种钱币的找零数量;
    /// * 找零量最大为255,超过255 时上报为255;
    /// * 找零量单位为“个”,代表可找零硬币的个数。
    /// </summary>
    public int 找零余量4
    {
      get
      {
        return m_data[18];
      }
    }

    /// <summary>
    /// 找零余量“找零量1#”…“找零量6#”,分别对应硬币器信息info_rpt.type=17 的“找零
    /// 1#”…“找零6#”中每种钱币的找零数量;
    /// * 找零量最大为255,超过255 时上报为255;
    /// * 找零量单位为“个”,代表可找零硬币的个数。
    /// </summary>
    public int 找零余量5
    {
      get
      {
        return m_data[19];
      }
    }

    /// <summary>
    /// 找零余量“找零量1#”…“找零量6#”,分别对应硬币器信息info_rpt.type=17 的“找零
    /// 1#”…“找零6#”中每种钱币的找零数量;
    /// * 找零量最大为255,超过255 时上报为255;
    /// * 找零量单位为“个”,代表可找零硬币的个数。
    /// </summary>
    public int 找零余量6
    {
      get
      {
        return m_data[20];
      }
    }

  }
}

以上就是c#实现自动售货机接口的代码,需要的朋友可以来学习。