状态机

1.发送数据和接收数据用2个状态机实现;

2. 增加了当数据发送以后指定的间隔内连续发送3次,如果没有收到下位机的回复则放弃;

3.取消使用定时器Timer类,自己写定时器;

using System;
using System.Collections;
using System.Threading;
using System.Xml;
using NLog;
using System.Timers;
using System.IO;
using System.Runtime.InteropServices;
using MSCommLib;

namespace equipment
{
 /// <summary>
 /// Desc:还书箱模块(用2个状态机实现)
 /// Author:周陶
 /// Date:2006-9-11
 /// Version:1.0
 /// </summary>
 public class RestoreBook : ThreadBase,EquipmentIF
 { 
  #region 配置文件
  private const string m_config_file = "..//configure//equipment//RestoreBook_config.xml";
  private const string m_const_node_name = "/configure/restorebooks/restorebook";
  private const string m_const_comport = "/configure/restorebooks/restorebook/communication";
  private static Logger logger = LogManager.GetCurrentClassLogger();
  #endregion

  #region 指令
  private const string TCU_BOX_STATUS = "41";
  private const string TCU_BOOK_STATUS = "40";
  private const string TCU_CHECKMAG_STATUS = "42";
  private const string TCU_DOOR_STATUS = "43";
  private const string TCU_BOOK_MOVE = "23";
  private const string TCU_RUN = "22";
  private const string TCU_RESET = "21";
  private const string TCU_END = "26";
  private const string TCU_CHECK_STATE = "24";
  #endregion

  #region 响应码
  private const string CE_OK = "0";
  private const string CE_CHECKERROR = "1";
  private const string CE_BADCOMMAND = "2"; //命令错误
  private const string CE_BADPARAM = "3"; //参数错误
  private const string CE_EXECUTE = "4";  //执行命令条件不足
  private const string CE_UNKNOWN = "5";
  private const string CE_NOCOMM = "6";
  #endregion

  #region 维护门状态
  private const string TCU_DOOR_OPENED = "1";
  private const string TCU_DOOR_CLOSED = "0";
  #endregion

  #region 检磁
  private const string E_ERROR = "1";
  private const string E_OK = "0";
  #endregion

  #region 书运行位置状态
  private const string E_READER_POSITION = "1";
  private const string E_WITHDRAW = "2";
  private const string E_READY_WITHDRAW = "3";
  private const string E_FORWARD = "4";
  private const string E_BOOK_ENTRY_ALL = "5";
  private const string E_BLOCK_BEFORE_READER = "11";
  private const string E_BLOCK_BEFORE_BOX = "12";
  private const string E_TIMEOUT_READER_POSITION = "13";
  private const string E_TIMEOUT_WAITING_ENTRY = "14";
  private const string E_TIMEOUT_ENTRY = "15";
  #endregion

  #region 还书箱状态
  private const string E_BOX_FULL = "1";
  private const string E_BOX_OK = "0";
  #endregion

  /*****************************************************************************/
  MSCommLib.MSCommClass mc = new MSCommLib.MSCommClass();

  ArrayList m_bytelist = new ArrayList();
  byte[] m_data = new byte[11];
  /*****************************************************************************/

  /*****************************系统定时器**************************************/
  private bool IS_RESPONSED = true;    //是否已经应答
  private int m_counter = 0;      //用于计算3次消息发送
  private string m_name = "";      //响应指令名称
  /*****************************************************************************/

  /******************************自定义定时器***********************************/
  BatchTimer t_time = null;      //分片定时器
  ResponseTimer m_responsetimer = null;   //响应定时器
  /*****************************************************************************/

  /****************************状态机*******************************************/
  #region 接收数据状态机
  private const string R_WAITING = "等待";
  private const string R_RECEIVING = "接收中";
  private const string R_RECEIVEALL = "全部接收";
  private const string R_BATCHTIMEOUT = "分片超时";
  private const string R_RESPONSETIMEOUT = "响应超时";
  private const string R_ERRORCOMMAND = "错误命令";
  private const string R_ERRORSTATUS = "错误状态";
  #endregion

  #region 发送数据状态机
  private const string S_WAITING = "等待";
  private const string S_RECEIVEALL = "全部接收";  
  private const string S_RESPONSETIMEOUT = "响应超时"; 
  private const string S_SEND = "已发送";
  private const string S_RESEND = "重复发送";
  private const string S_SENDCOUNT = "超过3次发送次数";
  private const string S_BATCHTIMEOUT = "分片超时";
  #endregion
  /*****************************************************************************/

  /****************************初始化状态机状态*********************************/
  string state1=S_WAITING,state2=R_WAITING;
  byte [] m_byte = new byte[11];
  /*****************************************************************************/


  [DllImport("user32.dll",EntryPoint="MessageBox")]
  public static extern void MsgBox(int hWnd,String text,String caption,uint type);

  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="i_name"></param>
  public RestoreBook(string i_name):base(i_name)
  {
   this.InitCommonPort();
   t_time = new BatchTimer();
   m_responsetimer = new ResponseTimer();
  }


  /// <summary>
  /// 从配置文件中读取配置端口号
  /// </summary>
  /// <param name="t_config"></param>
  /// <returns></returns>
  private string getComPortConfig(string t_config)
  {
   XmlTextReader reader = new XmlTextReader(m_config_file);
   XmlDocument xmldoc = new XmlDocument();
   xmldoc.Load(reader);
   reader.Close();

   XmlNode t_node = xmldoc.SelectSingleNode(t_config);

   string port = t_node.InnerText;
   return port;
  }
 
  /// <summary>
  /// 取出指定长度的数据
  /// </summary>
  /// <param name="o_bytelist"></param>
  /// <param name="length"></param>
  private void GetReceiveData(ref byte[] o_bytelist,int length)
  {
   for(int i=0;i<length;i++)
   {
    o_bytelist[i] = (byte)m_bytelist[i];
   }
   m_bytelist.RemoveRange(0,length);
  }


  /// <summary>
  /// 接收MCU主动发送的消息、解析、封装成对象消息发送给Session层
  /// </summary>
  protected override void process()
  {
   //以40,41,42,43开头的指令属于主动上报状态的命令
   int count = 0;

   lock(state2) //接收数据状态机
   {
    switch(state2)
    {
     #region 接收中
     case R_RECEIVING: 
     {
      count = m_bytelist.Count; //计算缓冲区中接收到的数据长度

      if(count == 0)
      {
       state2 = R_WAITING;
      }
      else if(count < 11) //如果长度<11 接收不完整,启动分片定时器
      {
       #region 分片定时器       
       if(!t_time.IsStart)
       {
        t_time.Start();
        t_time.Intenal = 2000;
        logger.Debug("/n分片定时器已启动!");
       }
       else
       {
        if(t_time.IsTimeOut)
        {
         state1 = S_BATCHTIMEOUT;
        }
       }
       #endregion       
      }
      else if(count >= 11)
      {
       this.GetReceiveData(ref m_byte,11);

       byte t_command = m_byte[2];  //获得消息的命令用来判断是主动上报消息还是响应消息

       if(m_byte[0] == 0x82)
       {
        if(m_byte[10] == 0x83)
        {
         if(verifyCRC(m_byte))
         {
          if(t_command == 0x40 || t_command == 0x41 || t_command == 0x42 || t_command == 0x43)
          {
           logger.Debug("/n正确的状态指令 : [" + Utilities.ByteArrayToHexString(m_byte) + "]");
          }
          else
          {
           logger.Debug("/n正确的响应指令 : [" + Utilities.ByteArrayToHexString(m_byte) + "]");
           m_counter = 0;
           m_responsetimer.Stop(); 
          }
          state1 = S_RECEIVEALL;  //将发送状态机状态改为全部接收
          state2 = R_RECEIVING;  //将接收状态机状态改为接收中
         }
         else
         {
          if(t_command == 0x40 || t_command == 0x41 || t_command == 0x42 || t_command == 0x43)
          {
           state2 = R_ERRORSTATUS;
          }
          else
          {
           state2 = R_ERRORCOMMAND;
          }
         }
        }
        else
        {
         if(t_command == 0x40 || t_command == 0x41 || t_command == 0x42 || t_command == 0x43)
         {
          state2 = R_ERRORSTATUS;
         }
         else
         {
          state2 = R_ERRORCOMMAND;
         }
        }
       }
       else
       {
        if(t_command == 0x40 || t_command == 0x41 || t_command == 0x42 || t_command == 0x43)
        {
         state2 = R_ERRORSTATUS;
        }
        else
        {
         state2 = R_ERRORCOMMAND;
        }
       }
      }      
      break;
     }
     #endregion

     #region 接收命令错误
     case R_ERRORCOMMAND:
     {
      state2 = R_RECEIVING;  //接收中
      logger.Debug("/n响应命令格式错误![" + Utilities.ByteArrayToHexString(m_byte) + "]");
      this.clearArray(ref m_byte);
      break;
     }
     #endregion

     #region 接收状态错误
     case R_ERRORSTATUS:
     {
      state2 = R_RECEIVING;  //接收中
      logger.Debug("/n接收状态格式错误! [" + Utilities.ByteArrayToHexString(m_byte) + "]");
      this.clearArray(ref m_byte);
      break;
     }
     #endregion
    }
   }

   lock(state1) //发送数据状态机
   {
    switch(state1)
    {
     #region 已发送
     case S_SEND:
     {      
      if(!m_responsetimer.IsStart)
      {
       m_responsetimer.Start();
       m_responsetimer.Intenal = 3000;
       IS_RESPONSED = false;
       logger.Debug("/n响应超时定时器已启动!");
      }
      break;
     }
     #endregion

     #region 接收完毕并通过验证
     case S_RECEIVEALL:
     {
      sendMail(m_byte);   //通知上层
      state1 = S_WAITING;
      logger.Debug("/n已接收 : " + Utilities.ByteArrayToHexString(m_byte) + "]");
      this.clearArray(ref m_byte);
      break;
     }
     #endregion
     
     #region 重复发送3次
     case S_RESEND:
     {
      Thread.Sleep(1000);
      mc.Output = m_data;

      state1 = S_WAITING;
      logger.Debug("/n重复发送指令 : [" + Utilities.ByteArrayToHexString(m_data) + "] "+m_counter+"次!");
      break;
     }
     #endregion
     
     #region 响应超时
     case S_RESPONSETIMEOUT:
     {      
      state1 = S_WAITING;
      m_responsetimer.Stop();
      m_counter = 0;
      IS_RESPONSED = true;
      this.clearArray(ref m_data);
      logger.Debug("/n响应已超时!");
      break;
     }
     #endregion

     #region 发送次数超过3次
     case S_SENDCOUNT:
     {      
      m_counter = 0;
      m_responsetimer.Stop(); 
      IS_RESPONSED = true;
      state1 = S_WAITING;  //将状态设为等待状态
      logger.Debug("命令无应答,定时器已停止!");
      MsgBox(0,"命令无应答!","提醒",0);
      break;
     }
     #endregion

     #region 分片超时
     case S_BATCHTIMEOUT:
     {
      state1 = S_WAITING;  //将接收状态机改为等待状态
      this.GetReceiveData(ref m_byte,count);
      //m_bytelist.RemoveRange(0,count); //清除缓冲区
      IS_RESPONSED = true;
      t_time.Stop();
      logger.Debug("/n不完整的"+m_name+"响应指令 : ["+Utilities.ByteArrayToHexString(m_byte) + "],分片定时器已停止!");
      this.clearArray(ref m_byte);
      break;
     }
     #endregion
    }
   }

   #region 响应定时器
   if(IS_RESPONSED == false)     //没有响应
   {
    if(m_responsetimer.IsStart)    //超时定时器已启动
    {
     if(m_counter < 3)     //发送次数小于3
     {
      if(m_responsetimer.IsTimeOut) //超时
      {
       state1 = S_RESPONSETIMEOUT; //通知发送状态机响应超时
      }
      else       //没有超时但没有收到响应
      {
       state1 = S_RESEND;   //通知发送状态机再发一次
       m_counter ++;    //次数+1
      }
     }
     else        //超过3次
     {
      state1 = S_SENDCOUNT;   //通知发送状态机停止发送,关闭定时器
     }
    }
   }
   #endregion

  }
 
  /// <summary>
  /// check the data CRC
  /// </summary>
  /// <returns></returns>
  private bool verifyCRC(byte[] i_byte)
  {
   #region 接收

   byte t1 = i_byte[8];
   byte t2 = i_byte[9];
   byte [] data = {0x08,i_byte[2],i_byte[4],i_byte[5],i_byte[6],i_byte[7]};
   byte [] crcData = Utilities.CRC(data,data.Length);
   if(t1==crcData[0] && t2==crcData[1])
   {
    return true;
   }
   else
   {
    return false;
   }

   #endregion
  }

    
  /// <summary>
  /// clear array
  /// </summary>
  /// <param name="o_data"></param>
  private void clearArray(ref byte[]o_data)
  {
   for(int i=0;i<o_data.Length;i++)
   {
    o_data[i] =0;
   }
  }

  
  /// <summary>
  /// send mail to session
  /// </summary>
  /// <param name="inData"></param>
  private void sendMail(byte[] inData)
  {
   //构造命令
   Mail t_mail = null;

   MailHandlerIF t_mail_handler = new RestoreBookMailHandler();

   string t_cmd = inData[2].ToString("X");   //指令
    
   string t_paramter = inData[7].ToString("X"); //参数

   #region
   switch(t_cmd)
   {
    case TCU_BOX_STATUS:        //主 动 上 报 回 收 箱 状 态
    {
     #region
      
     switch(t_paramter)
     {
      case E_BOX_FULL:
      {
       //箱满

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOX_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_BOX_FULL);
                
       response("BOX",E_BOX_FULL);        
        
       break;
      }
      case E_BOX_OK:
      {
       //正常

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOX_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_BOX_OK);
       
       response("BOX",E_BOX_OK);

       break;
      }
     }
      
     this.m_send_mailbox.delivery(t_mail);

     break;

     #endregion
    }
    case TCU_BOOK_STATUS:       //TCU 主 动 上 报 书 运 行 位 置 状 态
    {
     #region
      
     switch(t_paramter)
     {
      case E_READER_POSITION:
      {
       //书已到读卡位置

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_READER_POSITION);

       response("BOOK_STATUS",E_READER_POSITION);

       break;
      }
      case E_WITHDRAW:
      {
       //书已经从入口被取走
     
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_WITHDRAW);
       
       response("BOOK_STATUS",E_WITHDRAW);

       break;
      }
      case E_READY_WITHDRAW:
      {
       //书已在入口处等待被取走

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_READY_WITHDRAW);
        
       response("BOOK_STATUS",E_READY_WITHDRAW);

       break;
      }
      case E_FORWARD:
      {
       //书已收入回收箱
        
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_FORWARD);
       
       response("BOOK_STATUS",E_FORWARD);

       break;
      }
      case E_BOOK_ENTRY_ALL:
      {
       //书完全进入
        
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_BOOK_ENTRY_ALL);
       
       response("BOOK_STATUS",E_BOOK_ENTRY_ALL);

       break;
      }
      case E_BLOCK_BEFORE_READER:
      {
       //读卡位置到入口之间发生堵塞故障

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_BLOCK_BEFORE_READER);
       
       response("BOOK_STATUS",E_BLOCK_BEFORE_READER);

       break;
      }
      case E_BLOCK_BEFORE_BOX:
      {
       //读卡位置到回收箱之间发生堵塞故障

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_BLOCK_BEFORE_BOX);
       
       response("BOOK_STATUS",E_BLOCK_BEFORE_BOX);

       break;
      }
      case E_TIMEOUT_READER_POSITION:
      {
       //读卡位置等待超时

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_TIMEOUT_READER_POSITION);
       
       response("BOOK_STATUS",E_TIMEOUT_READER_POSITION);

       break;
      }
      case E_TIMEOUT_WAITING_ENTRY:
      {
       //书等待进入超时

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_TIMEOUT_WAITING_ENTRY);
       
       response("BOOK_STATUS",E_TIMEOUT_WAITING_ENTRY);

       break;
      }
      case E_TIMEOUT_ENTRY:
      {
       //书在入口处等待超时

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_TIMEOUT_ENTRY);
       
       response("BOOK_STATUS",E_TIMEOUT_ENTRY);

       break;
      }
     }
      
     this.m_send_mailbox.delivery(t_mail);

     break;

     #endregion
    }
    case TCU_CHECKMAG_STATUS:   //主 动 上 报 检 磁 状 态
    {
     #region
      
     switch(t_paramter)
     {
      case E_ERROR:
      {
       //检磁失败

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_CHECKMAG_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_ERROR);
      
       response("CHECKMAG",E_ERROR);

       break;
      }
      case E_OK:
      {
       //检磁成功
        
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_CHECKMAG_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_OK);
       
       response("CHECKMAG",E_OK);

       break;
      }
     }

     this.m_send_mailbox.delivery(t_mail);

     break;
      
     #endregion
    }
    case TCU_DOOR_STATUS:       //主 动 上 报 维 护 门 状 态
    {
     #region
      
     switch(t_paramter)
     {
      case TCU_DOOR_OPENED:
      {
       //门被打开

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_DOOR_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_DOOR_OPEN);
       
       response("DOOR_STATUS",TCU_DOOR_OPENED);

       break;
      }
      case TCU_DOOR_CLOSED:
      {
       //门关闭

       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_DOOR_STATUS,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_DOOR_CLOSE);
       
       response("DOOR_STATUS",TCU_DOOR_CLOSED);

       break;
      }
     }

     this.m_send_mailbox.delivery(t_mail);

     break;
      
     #endregion
    }
    case TCU_BOOK_MOVE:         //指 导 书 运 行 状 态
    {
     #region
     switch(t_paramter)
     {
      case CE_OK://正常
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_MOVE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_OK);
       
       break;
      }
      case CE_CHECKERROR://校验错误
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_MOVE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_CHECKERROR);
       
       break;
      }
      case CE_BADCOMMAND://命令错误
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_MOVE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_BADCOMMAND);
       
       break;
      }
      case CE_BADPARAM://参数错误
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_MOVE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_BADPARAM);
       
       break;
      }
      case CE_EXECUTE://命令执行条件不足
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_MOVE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_EXECUTE);
       
       break;
      }
      case CE_UNKNOWN://其他错误
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_MOVE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_UNKNOWN);
       
       break;
      }
      case CE_NOCOMM://通讯故障
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_BOOK_MOVE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_NOCOMM);
       
       break;
      }
     }

     this.m_send_mailbox.delivery(t_mail);

     break;
     #endregion
    }
    case TCU_RUN:               //登 陆 成 功
    {
     #region
     switch(t_paramter)
     {
      case CE_OK://正常
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_RUN,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_OK);
       
       this.m_send_mailbox.delivery(t_mail);

       break;
      }
     }
     break;
     #endregion
    }
    case TCU_RESET:             //复 位
    {
     #region
     switch(t_paramter)
     {
      case CE_OK://正常
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_RESET,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_OK);
       
       this.m_send_mailbox.delivery(t_mail);

       break;
      }
     }     
     break;
     #endregion
    }
    case TCU_END:               //结 束
    {
     #region
     switch(t_paramter)
     {
      case CE_OK://正常
      {
       t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_END,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.ErrorParameter.E_TCU_OK);
       
       this.m_send_mailbox.delivery(t_mail);

       break;
      }
     }     
     break;
     #endregion
    }
    case TCU_CHECK_STATE:  //检 查 设 备 状 态
    {
     byte p4 = inData[7];

     if((p4 & 0x02) == 0)
     {
      t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_CHECK_STATE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_BOX_COVER);
     
      this.m_send_mailbox.delivery(t_mail);
     }
     if((p4 & 0x04) == 0)
     {
      t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_CHECK_STATE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_DOOR_COVER);
     
      this.m_send_mailbox.delivery(t_mail);
     }
     if((p4 & 0x08) == 0)
     {
      t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_CHECK_STATE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_CHECKMAG_CONVER);
     
      this.m_send_mailbox.delivery(t_mail);
     }
     if((p4 & 0x10) == 0)
     {
      t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_CHECK_STATE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_READER_CONVER);
     
      this.m_send_mailbox.delivery(t_mail);
     }
     if((p4 & 0x20) == 0)
     {
      t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_CHECK_STATE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_BOX_ENTRY1_CONVER);
     
      this.m_send_mailbox.delivery(t_mail);
     }
     if((p4 & 0x40) == 0)
     {
      t_mail = t_mail_handler.CreateMail(MailInfo.Type.RestoreBook,MailInfo.Name.E_TCU_CHECK_STATE,this.m_send_mailbox,this.m_receive_mailbox,MailInfo.E_TCU_Parameter.E_BOX_ENTRY2_COVER);
     
      this.m_send_mailbox.delivery(t_mail);
     }

     break;
    }
   }
   #endregion

   //发送命令
   //this.m_send_mailbox.delivery(t_mail);
  }


  /// <summary>
  /// init com
  /// </summary>
  private void InitCommonPort()
  { 
   try
   {
    string [] t_comport = this.getComPortConfig(m_const_comport).Split(':');
    mc.CommPort = Convert.ToInt16( t_comport[0].Substring(3,1) ); //4
    mc.Settings = t_comport[1] ;     //38400,n,8,1
    mc.RThreshold = 1;        //每接收一个字符则激发OnComm()事件
    mc.DTREnable = true;
    mc.Handshaking = MSCommLib.HandshakeConstants.comNone;    
    mc.InputMode = MSCommLib.InputModeConstants.comInputModeBinary;   //二进制
    mc.InBufferSize = 1024;
    mc.InputLen = 0;        //决定每次Input读入的字符个数,缺省为0,表示读取接收缓冲区的全部内容
    //mc.InputLen = 1;        //一次读取一个
    mc.NullDiscard = false;
    mc.OnComm +=new MSCommLib.DMSCommEvents_OnCommEventHandler(mc_OnComm);  //注册一个OnComm事件
   
    try
    {
     mc.PortOpen = true;  //打开串口
     
     logger.Debug("串口已打开!");
    }
    catch
    {
     logger.Debug("串口打开失败!");
    }
   }
   catch(Exception ex)
   {
    logger.Debug(ex.Message);
   }
  }


  /// <summary>
  /// release resource
  /// </summary>
  public override void shutDown()
  {
   if(mc.PortOpen)
    mc.PortOpen = false;
  }


  /// <summary>
  /// receive the data from session layer then parse、create com data and send to MCU
  /// </summary>
  /// <param name="i_mail"></param>
  protected override void commonMailArriveProcess(Mail i_mail)
  {
   MailInfo.Name t_mail_name = i_mail.m_mail_name;         //mail name(command)
   
   string t_book_parameter = (string)i_mail.m_parameter;   //parameter

   byte [] data = {0x08,0x00,0x00,0x00,0x00,0x00};
   byte [] outData = {0x02,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03};
   byte [] crcData = null;
   byte [] cData = null;

   #region
   switch(t_mail_name)
   {
    case MailInfo.Name.E_TCU_RESET:         //复位
    {
     #region
     
     data[1] = 0x21;
     crcData = Utilities.CRC(data,data.Length);   
     outData[2] = 0x21;
     outData[8] = crcData[0];
     outData[9] = crcData[1];
   
     mc.Output = outData;

     logger.Debug("/n复位 : [" + Utilities.ByteArrayToHexString(outData) + "]");

     break;
     
     #endregion
    }
    case MailInfo.Name.E_TCU_RUN:           //登陆成功
    {
     #region
     
     data[1] = 0x22;
     crcData = Utilities.CRC(data,data.Length);
     outData[2] = 0x22;
     outData[8] = crcData[0];
     outData[9] = crcData[1];

     mc.Output = outData;

     m_name = "登陆成功";
     logger.Debug("/n发送登陆成功指令 : [" + Utilities.ByteArrayToHexString(outData) + "]");

     /***********************************************************************************/
     outData.CopyTo(m_data,0); //将消息复制到全局变量数组中,以后用来判断改消息是否回复
     
     state1 = S_SEND;   //将发送状态机的状态改为已发送
     /***********************************************************************************/

     break;

     #endregion
    }
    case MailInfo.Name.E_TCU_CHECK_STATE:   //检查设备状态
    {
     #region
     
     data[1] = 0x24;
     crcData = Utilities.CRC(data,data.Length);
     outData[2] = 0x24;
     outData[8] = crcData[0];
     outData[9] = crcData[1];
   
     mc.Output = outData;

     m_name = "检查设备状态";
     logger.Debug("/n检查设备状态 : [" + Utilities.ByteArrayToHexString(outData) + "]");

     /************************************************************************************/
     outData.CopyTo(m_data,0); //将消息复制到全局变量数组中,以后用来判断改消息是否回复
     
     state1 = S_SEND;   //将发送状态机的状态改为已发送
     /************************************************************************************/

     break;
     
     #endregion
    }
    case MailInfo.Name.E_TCU_BOOK_MOVE:     //指导书运动
    {
     #region
     
     switch(t_book_parameter)
     {
      case "E_BACK":      //书已退到入口
      {
       #region
       
       data[1] = 0x23;
       data[5] = 0x01;
       crcData = Utilities.CRC(data,data.Length);
       outData[2] = 0x23;
       outData[7] = 0x01;
       outData[8] = crcData[0];
       outData[9] = crcData[1];

       logger.Debug("/n书已退到入口 : ["+ Utilities.ByteArrayToHexString(outData) + "]");

       break;
       #endregion
      }
      case "E_FORWARD":   //收入回收箱
      {
       #region
          
       data[1] = 0x23;
       data[5] = 0x02;
       crcData = Utilities.CRC(data,data.Length);
       outData[2] = 0x23;
       outData[7] = 0x02;
       outData[8] = crcData[0];
       outData[9] = crcData[1];

       logger.Debug("/n收入回收箱 : ["+ Utilities.ByteArrayToHexString(outData) + "]");

       break;
       #endregion
      }
     }
     
     mc.Output = outData;

     /************************************************************************************/
     outData.CopyTo(m_data,0); //将消息复制到全局变量数组中,以后用来判断改消息是否回复

     state1 = S_SEND;   //将发送状态机的状态改为已发送
     /************************************************************************************/

     break;

     #endregion
    }
    case MailInfo.Name.E_TCU_BOOK_STATUS:   //主动上报书运行位置状态
    {
     #region
     
     switch(t_book_parameter)
     {
      case "E_READER_POSITION":   //书已到读卡位置
      {
       #region
      
       data[1] = 0x40;
       data[5] = 0x01;
       cData = Utilities.CRC(data,data.Length);

       outData[0] = 0x82;
       outData[2] = 0x40;
       outData[7] = 0x01;
       outData[8] = cData[0];
       outData[9] = cData[1];
       outData[10] = 0x83;

       logger.Debug("/n书已到读卡位置 : [" + Utilities.ByteArrayToHexString(outData)  + "]");

       break;
       #endregion
      }
      case "E_WITHDRAW":     //书已从入口被取走
      {
       #region
       
       data[1] = 0x40;
       data[5] = 0x02;
       cData = Utilities.CRC(data,data.Length);

       outData[0] = 0x82;
       outData[2] = 0x40;
       outData[7] = 0x02;
       outData[8] = cData[0];
       outData[9] = cData[1];
       outData[10] = 0x83;

       logger.Debug("/n书已从入口被取走 : [" + Utilities.ByteArrayToHexString(outData) + "]");

       break;
       #endregion
      }
      case "E_READY_WITHDRAW":   //书已在入口处等待被取走
      {
       #region
       
       data[1] = 0x40;
       data[5] = 0x03;
       cData = Utilities.CRC(data,data.Length);

       outData[0] = 0x82;
       outData[2] = 0x40;
       outData[7] = 0x03;
       outData[8] = cData[0];
       outData[9] = cData[1];
       outData[10] = 0x83;

       logger.Debug("/n书已在入口处等待被取走 : [" + Utilities.ByteArrayToHexString(outData) +"]");

       break;
       #endregion
      }
      case "E_FORWARD":     //书已收入回收箱
      {
       #region
      
       data[1] = 0x40;
       data[5] = 0x04;
       cData = Utilities.CRC(data,data.Length);

       outData[0] = 0x82;
       outData[2] = 0x40;
       outData[7] = 0x04;
       outData[8] = cData[0];
       outData[9] = cData[1];
       outData[10] = 0x83;

       logger.Debug("/n书已收入回收箱 : [" + Utilities.ByteArrayToHexString(outData) +"]");

       break;
       #endregion
      }
      case "E_BLOCK_BEFORE_READER":  //读卡位置到入口之间发生堵塞故障
      {
       #region
       
       data[1] = 0x40;
       data[5] = 0x011;
       cData = Utilities.CRC(data,data.Length);

       outData[0] = 0x82;
       outData[2] = 0x40;
       outData[7] = 0x11;
       outData[8] = cData[0];
       outData[9] = cData[1];
       outData[10] = 0x83;

       logger.Debug("/n读卡位置到入口之间发生堵塞故障 : [" + Utilities.ByteArrayToHexString(outData) +"]");
 
       break;
       #endregion
      }
      case "E_BLOCK_BEFORE_BOX":   //读卡位置到回收箱之间发生堵塞故障
      {
       #region
              
       data[1] = 0x40;
       data[5] = 0x12;
       cData = Utilities.CRC(data,data.Length);

       outData[0] = 0x82;
       outData[2] = 0x40;
       outData[7] = 0x12;
       outData[8] = cData[0];
       outData[9] = cData[1];
       outData[10] = 0x83;

       logger.Debug("/n读卡位置到回收箱之间发生堵塞故障 : [" + Utilities.ByteArrayToHexString(outData) +"]");

       break;
       #endregion
      }
      case "E_TIMEOUT_READER_POSITION":   //读卡位置等待超时
      {
       #region
       
       data[1] = 0x40;
       data[5] = 0x13;
       cData = Utilities.CRC(data,data.Length);

       outData[0] = 0x82;
       outData[2] = 0x40;
       outData[7] = 0x13;
       outData[8] = cData[0];
       outData[9] = cData[1];
       outData[10] = 0x83;

       logger.Debug("/n读卡位置等待超时 : [" + Utilities.ByteArrayToHexString(outData)+"]");

       break;
       #endregion
      }
      case "E_TIMEOUT_WAITING_ENTRY":  //书等待进入超时
      {
       #region
       
       data[1] = 0x40;
       data[5] = 0x14;
       cData = Utilities.CRC(data,data.Length);

       outData[0] = 0x82;
       outData[2] = 0x40;
       outData[7] = 0x14;
       outData[8] = cData[0];
       outData[9] = cData[1];
       outData[10] = 0x83;

       logger.Debug("/n书等待进入超时 : [" + Utilities.ByteArrayToHexString(outData)+"]");

       break;
       #endregion
      }
      case "E_TIMEOUT_ENTRY":    //书在入口处等待超时
      {
       #region
       
       data[1] = 0x40;
       data[5] = 0x15;
       cData = Utilities.CRC(data,data.Length);

       outData[0] = 0x82;
       outData[2] = 0x40;
       outData[7] = 0x15;
       outData[8] = cData[0];
       outData[9] = cData[1];
       outData[10] = 0x83;

       logger.Debug("/n书在入口处等待超时 : [" + Utilities.ByteArrayToHexString(outData) + "]");

       break;
       #endregion
      }
      default:       //书已进入还书箱
      {
       #region
          
       data[1] = 0x23;
       cData = Utilities.CRC(data,data.Length);

       outData[2] = 0x23;
       outData[8] = cData[0];
       outData[9] = cData[1];

       logger.Debug("/n书已进入还书箱 : [" + Utilities.ByteArrayToHexString(outData) + "]");

       break;
       #endregion
      }
     }

     mc.Output = outData;
     
     break;

     #endregion     
    }
    case MailInfo.Name.E_TCU_END:           //结束
    {
     #region

     data[1] = 0x26;
     crcData = Utilities.CRC(data,data.Length);
     outData[2] = 0x26;
     outData[8] = crcData[0];
     outData[9] = crcData[1];

     mc.Output = outData;

     m_name = "结束";     
     logger.Debug("/n结束 : [" + Utilities.ByteArrayToHexString(outData) + "]");

     /*************************************************************************************/
     outData.CopyTo(m_data,0); //将消息复制到全局变量数组中,以后用来判断改消息是否回复
     
     state1 = S_SEND;   //将发送状态机的状态改为已发送
     /*************************************************************************************/

     break;

     #endregion
    }
   }
   #endregion
  }

  /// <summary>
  /// 对下位机主动发送的命令的响应
  /// </summary>
  /// <param name="command">命令</param>
  /// <param name="parameter">参数</param>
  private void response(string command,string parameter)
  {
   byte [] crcData = null; //校验码
   byte [] data = null; //参与计算校验码值参数
   byte [] outData = null; //响应消息

   switch(command)
   {
    case "BOX":    //还书箱状态
    {
     switch(parameter)
     {
       #region
      case E_BOX_FULL: //还书箱已满
      {
       data = new byte[]{0x08,0x41,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x41,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_BOX_OK:  //还书箱正常
      {
       data = new byte[]{0x08,0x41,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x41,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
       #endregion
     }

     break;
    }

    case "BOOK_STATUS":  //书运行状态
    {
     switch(parameter)
     {
       #region

      case E_READER_POSITION://书已到读卡位置
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_WITHDRAW: //书从入口被取走
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_READY_WITHDRAW:  //书已在入口处被等待取走
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_FORWARD:  //书已进入回收箱
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_BOOK_ENTRY_ALL:  //书已完全进入
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_BLOCK_BEFORE_READER:  //读卡位置到入口之间发生堵塞故障
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_BLOCK_BEFORE_BOX: //读卡位置到回收箱之间发生堵塞故障
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_TIMEOUT_READER_POSITION:  //读卡位置等待超时
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_TIMEOUT_WAITING_ENTRY: //书等待进入超时
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_TIMEOUT_ENTRY: //书在入口处等待超时
      {
       data = new byte[]{0x08,0x40,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x40,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }

       #endregion
     }

     break;
    }

    case "CHECKMAG":  //检磁状态
    {
     switch(parameter)
     {
       #region
      case E_ERROR:
      {
       data = new byte[]{0x08,0x42,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x42,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
      case E_OK:
      {
       data = new byte[]{0x08,0x42,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x42,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
       #endregion
     }

     break;
    }
     
    case "DOOR_STATUS":  //维护门状态
    {
     switch(parameter)
     {
       #region
      case TCU_DOOR_OPENED:
      {
       data = new byte[]{0x08,0x43,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x43,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }

      case TCU_DOOR_CLOSED:
      {
       data = new byte[]{0x08,0x43,0x00,0x00,0x00,0x00};
       crcData = Utilities.CRC(data,data.Length);
       outData = new byte[]{0x02,0x08,0x43,0x00,0x00,0x00,0x00,0x00,crcData[0],crcData[1],0x03};
       break;
      }
       #endregion
     }

     break;
    }
   }

   mc.Output = outData;

  }

  
   /// <summary>
  /// receive data from com
  /// </summary>
  private void mc_OnComm()
  {
   byte [] t_byte = (byte[])mc.Input;  //接收数据清空缓冲区

   for(int i = 0;i<t_byte.Length;i++)
   {
    Monitor.Enter(m_bytelist);
    m_bytelist.Add(t_byte[i]);
    Monitor.Exit(m_bytelist);
   }

   lock(state2)
   {
    if(t_byte.Length > 0)
    {
     state2 = R_RECEIVING; //有数据到达把状态改成正在接收
    }
   }
  }
 }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值