sessionlayer.cs

来自「zwave 无线通讯协议 PC controller 控制器源码」· CS 代码 · 共 718 行 · 第 1/2 页

CS
718
字号
//////////////////////////////////////////////////////////////////////////////////////////////// 
//
//          #######
//          #   ##    ####   #####    #####  ##  ##   #####
//             ##    ##  ##  ##  ##  ##      ##  ##  ##
//            ##  #  ######  ##  ##   ####   ##  ##   ####
//           ##  ##  ##      ##  ##      ##   #####      ##
//          #######   ####   ##  ##  #####       ##  #####
//                                           #####
//          Z-Wave, the wireless language.
//
//          Copyright Zensys A/S, 2005
//
//          All Rights Reserved
//
//          Description:   
//
//          Author:   Morten Damsgaard, Linkage A/S
//
//          Last Changed By:  $Author: jrm $
//          Revision:         $Revision: 1.7 $
//          Last Changed:     $Date: 2007/02/15 11:34:47 $
//
//////////////////////////////////////////////////////////////////////////////////////////////
#region Using directives

using System;
using System.Threading;
using System.Collections;
using System.Diagnostics;
using System.Resources;
using Zensys.ZWave.Logging;

#endregion

namespace Zensys.ZWave.Communication
{
  /// <summary>
  /// 
  /// </summary>
  public class SessionLayer : ISessionLayer, IFrameLayerAsyncCallback
  {
    private const int DEFAULT_TIMEOUT = 10000; // How long in ms to wait for an response
    
    // ---- Note ----
    // Sequence numbers are appended to the data frame at the _last_ position in the payload, 
    // just before the checksum byte.
    // Not all requests use sequence numbers
    // The response from the ZW-module sets the sequence number at the _first_ position in
    // the payload, just after the command ID
    private const byte MIN_SEQUENCE_NUMBER = 1;
    private const byte MAX_SEQUENCE_NUMBER = 127;
    private byte sequenceNumber = MIN_SEQUENCE_NUMBER;
    private IFrameLayer frameLayer;
    private DataPacket request;
    private DataFrame.CommandType command;
    private ISessionLayerAsyncCallback asyncCallback;
    private SessionStatistics stats;
    private DataPacketQueue queue;
    private ZWaveLogging log = ZWaveLogging.GetInstance("SessionLayer", false);
    private DataFrame lastDataFrame = null;
    private bool _IsReady; 
   
    /// <summary>
    /// 
    /// </summary>
    public SessionLayer()
    {
    }
    
    /// <summary>
    /// 
    /// </summary>
    /// <param name="frameLayer"></param>
    /// <param name="transportLayer"></param>
    /// <param name="connectionString"></param>
    public void Open(IFrameLayer frameLayer, ITransportLayer transportLayer, String connectionString)
    {
      if (frameLayer == null)
      {
        throw new ArgumentNullException("frameLayer");
      }
      this.sequenceNumber = MIN_SEQUENCE_NUMBER;
      this.frameLayer = frameLayer;
      frameLayer.Open(transportLayer, connectionString);
      frameLayer.SetCallbackHandler(this);
      queue = new DataPacketQueue();
      stats = new SessionStatistics();
    }

    /// <summary>
    /// 
    /// </summary>
    public void Close()
    {
      frameLayer.Close();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public SessionStatistics GetStatistics()
    {
      lock (stats)
      {
        return new SessionStatistics(stats);
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="handler"></param>
    public void SetCallbackHandler(ISessionLayerAsyncCallback handler)
    {
      this.asyncCallback = handler;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="cmd"></param>
    /// <param name="request"></param>
    /// <returns></returns>
    public bool RequestWithNoResponse(DataFrame.CommandType cmd, DataPacket request)
    {
        try
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            lock (this)
            {
                // Construct and setup the new data frame...
                DataFrame frame = new DataFrame();
                frame.Type = DataFrame.FrameType.Request;
                frame.Command = cmd;
                // Add the data payload...
                frame.AddPayload(request.GetPayload());
                // Check if the sequence number should be appended at the last payload position...
                if (request.SequenceNumber > 0)
                    frame.AddPayload(request.SequenceNumber);
                stats.transmittedPackets++;
                return frameLayer.Write(frame);
            }
        }
        catch (FrameLayerException FLE)
        {
            throw new FrameLayerException("Error in RequestWithNoRepsonse :" + FLE.Message);
        }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="cmd"></param>
    /// <param name="request"></param>
    /// <param name="response"></param>
    /// <returns></returns>
    public TXStatus RequestWithResponse(DataFrame.CommandType cmd,
      DataPacket request,
      out DataPacket response)
    {
      if (request == null)
      {
        throw new ArgumentNullException("request");
      }  
      return RequestWithResponse(cmd, request, out response, false, DEFAULT_TIMEOUT);
    }
  
    /// <summary>
    /// 
    /// </summary>
    /// <param name="cmd"></param>
    /// <param name="request"></param>
    /// <param name="response"></param>
    /// <param name="sequenceCheck"></param>
    /// <returns></returns>
    public TXStatus RequestWithResponse(DataFrame.CommandType cmd, 
      DataPacket request, 
      out DataPacket response,
      bool sequenceCheck  )
    {
      if (request == null)
      {
        throw new ArgumentNullException("request");
      }  

      return RequestWithResponse(cmd, request, out response, sequenceCheck, DEFAULT_TIMEOUT);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="cmd"></param>
    /// <param name="request"></param>
    /// <param name="response"></param>
    /// <param name="sequenceCheck"></param>
    /// <param name="timeout"></param>
    /// <returns></returns>
    public TXStatus RequestWithResponse(DataFrame.CommandType cmd, 
      DataPacket request, 
      out DataPacket response,
      bool sequenceCheck, int timeout )
    {
       if (request == null)
       {
         throw new ArgumentNullException("request");
       }    

      IsReady = false;
      lock (this)
      {
        if (sequenceCheck) request.SequenceNumber = SequenceNumber++;

        lastDataFrame = null;
        queue.Clear();

        // Store the command...
        this.command = cmd;

        // Store the request...
        this.request = request;

        RequestWithNoResponse(cmd, request);

        response = null;

        // Wait for reponse from peer or timeout...
        if (queue.Dequeue(timeout, ref response))
        {
          this.command = 0;
          // Sequence number check...
          if (sequenceCheck && response.SequenceNumber != request.SequenceNumber)
          {
            IsReady = true;
            return TXStatus.ResMissing;   //false;
          }    
        }
        else
        {
          lock (stats) { stats.receiveTimeouts++; }
          IsReady = true;
          return TXStatus.NoAcknowledge; 
        }
        IsReady = true;
        return TXStatus.CompleteOk;
      } // lock
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="cmd"></param>
    /// <param name="request"></param>
    /// <param name="responses"></param>
    /// <returns></returns>
    public TXStatus RequestWithMultipleResponses(DataFrame.CommandType cmd,
      DataPacket request,
      ref DataPacket[] responses)
    {
      if (request == null)
      {
        throw new ArgumentNullException("request");
      }
      return RequestWithMultipleResponses(cmd, request, ref responses, false, DEFAULT_TIMEOUT);
    }
 
    /// <summary>
    /// 
    /// </summary>
    /// <param name="cmd"></param>
    /// <param name="request"></param>
    /// <param name="responses"></param>
    /// <param name="sequenceCheck"></param>
    /// <returns></returns>
    public TXStatus RequestWithMultipleResponses(DataFrame.CommandType cmd,
      DataPacket request,
      ref DataPacket[] responses,
      bool sequenceCheck)
    {
      if (request == null)
      {
        throw new ArgumentNullException("request");
      }
      return RequestWithMultipleResponses(cmd, request, ref responses, sequenceCheck, DEFAULT_TIMEOUT);
    }

      /// <summary>
      /// Requests a command which may give different numbers of callbacks.
      /// Supply with Responses array that have room for worst case number of callbacks
      /// </summary>
      /// <param name="cmd">Zwave Cmd</param>
      /// <param name="request">Parms for command</param>
      /// <param name="responses">Max number of responses</param>
      /// <param name="breakVal">Values to end one</param>
      /// <param name="sequenceCheck">if true use sequence check</param>
      /// <param name="timeout">Timeout in ms</param>
      /// <returns></returns>
    public TXStatus RequestWithVariableResponses(DataFrame.CommandType cmd,
        DataPacket request,
        ref DataPacket[] responses,
        byte[] breakVal,
        bool sequenceCheck,
        int timeout)
      {
          if (request == null)
          {
              throw new ArgumentNullException("request");
          }
          if (responses == null)
          {
              throw new ArgumentNullException("responses");
          }
          IsReady = false;
          lock (this)
          {
              if (sequenceCheck)
                  request.SequenceNumber = SequenceNumber++;

              lastDataFrame = null;
              queue.Clear();

              // Store the command...
              this.command = cmd;

              // Store the request...
              this.request = request;

              RequestWithNoResponse(cmd, request);

              // Wait for reponse from peer or timeout...
              for (int i=0; i<responses.Length; i++)
              {
                  if (queue.Dequeue(timeout, ref responses[i]))
                  {
                      // Strip the sequence number if used by the request
                      // The sequence number is placed as the first byte in the payload
                      if (sequenceCheck && responses[i].SequenceNumber > 0 && 
              responses[i].SequenceNumber != request.SequenceNumber)
                      {
                          IsReady = true;
                          return TXStatus.ResMissing;
                      }
                      if (i>0)
                      {
                          for (int n=0; n<breakVal.Length; n++)
                          {
                              if (responses[i].GetPayload()[0] == breakVal[n])
                              {
                                  return TXStatus.CompleteFail;
                              }
                          }
                      }
                  }
                  else
                  {
                      lock (stats)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?