sessionlayer.cs

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

CS
718
字号
                      {
                          stats.receiveTimeouts++;
                      }
                      IsReady = true;
                      return TXStatus.NoAcknowledge;
                      //return false;
                  }
              } // for
              IsReady = true;
              return TXStatus.CompleteOk;
              // return true;
          } // lock
      }


      /// <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 RequestWithVariableReturnsAndResponses(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)
                      {
                          stats.receiveTimeouts++;
                      }
                      IsReady = true;
                      return TXStatus.NoAcknowledge;
                      //return false;
                  }
              } // for
              IsReady = true;
              return TXStatus.CompleteOk;
              // return true;
          } // lock
      }



    /// <summary>
    /// 
    /// </summary>
    /// <param name="cmd"></param>
    /// <param name="request"></param>
    /// <param name="responses"></param>
    /// <param name="sequenceCheck"></param>
    /// <param name="timeout"></param>
    /// <returns></returns>
    public TXStatus RequestWithMultipleResponses(DataFrame.CommandType cmd,
      DataPacket request,
      ref DataPacket[] responses,
      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;
            }
          }
          else
          {
            lock (stats) { stats.receiveTimeouts++; }
            IsReady = true;
            return TXStatus.NoAcknowledge;
            //return false;
          }
        } // for
        IsReady = true;
        return TXStatus.CompleteOk;
       // return true;
      } // lock
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="frame"></param>
    public void FrameReceived(DataFrame frame)
    {
        if (frame == null)
        {
          throw new ArgumentNullException("frame");
        }    
      // Called from FrameLayer thread scope...
      lock (stats) { stats.receivedPackets++; }
       
      if (frame.Command == command)
      {
        // The peer ZWave module could be tranmitting the same frame twice.
        // so check if the frame was retransmitted from module
        if (lastDataFrame != null && lastDataFrame == frame)
        {
          lock (stats) { stats.duplicatePackets++; }
          log.Write("COM - Duplicate packet received...");
          return;
        }
        lastDataFrame = frame;
        DataPacket dp;
        // Check and extract (strip) sequence number from frame...
        if (request.SequenceNumber > 0 && frame.Type == DataFrame.FrameType.Request)
        {
          byte[] payload = frame.GetPayloadBuffer();
          byte[] data = new byte[payload.Length - 1];
          Array.Copy(payload, 1, data, 0, data.Length);

          dp = new DataPacket(data);
          dp.Timestamp = frame.Timestamp;
          dp.SequenceNumber = payload[0];
        }
        else
        {
          dp = new DataPacket(frame.GetPayloadBuffer());
          dp.Timestamp = frame.Timestamp;
        }
        // Put the DataPacket in the Queue...
        queue.Enqueue(dp);
      }
      else
        if (asyncCallback != null)
      {
        DataPacket dp = new DataPacket(frame.GetPayloadBuffer());
        dp.Timestamp = frame.Timestamp;
        asyncCallback.DataPacketReceived(frame.Command, dp);
        lock (stats) { stats.asyncPackets++; }
      }
    }

    private byte SequenceNumber
    {
      get
      {
        return sequenceNumber;
      }
      set
      {
        // Test if sequence number should wrap-around...
        if (sequenceNumber == MAX_SEQUENCE_NUMBER)
          sequenceNumber = MIN_SEQUENCE_NUMBER;
        else
          sequenceNumber = value;
      }
    }
    /// <summary>
    /// 
    /// </summary>
    public bool IsReady
    {
      get{return _IsReady;}
      set{_IsReady = value;}
    }

  }



  internal class DataPacketQueue
  {
    private Queue rxQueue;
    private TimeoutEvent responseEvent;

    public DataPacketQueue()
    {
      rxQueue = new Queue(10);
      responseEvent = new TimeoutEvent();
    }

    public void Enqueue(DataPacket packet)
    {
      lock (rxQueue.SyncRoot)
      {
        rxQueue.Enqueue(packet);
      }
      // Signal any waiting calls
      responseEvent.Set();
    }

    public bool Dequeue(int timeout, ref DataPacket packet)
    {
      bool rc = false;

      // First check if there is something in the queue...
      lock (rxQueue.SyncRoot)
      {
        if (rxQueue.Count > 0)
        {
          packet = (DataPacket)rxQueue.Dequeue();
          responseEvent.Reset(); // sync'ed with WaitOne in next call - TellITOnline DLI
          rc = true;
        }
      }
      
      if (!rc && responseEvent.WaitOne(timeout))
      {
        // Check that sequence number from the received packet equals the one transmitted...
        lock (rxQueue.SyncRoot)
        {
          if (rxQueue.Count > 0)
          {
            packet = (DataPacket)rxQueue.Dequeue();
            rc = true;
          }
        }
      }
      return rc;
    }

    public void Clear()
    {
      lock (rxQueue.SyncRoot)
      {
        rxQueue.Clear();
      }
      responseEvent.Reset();
    }
  }
  
  internal class TimeoutEvent
  {
    private AutoResetEvent responseEvent = new AutoResetEvent(false);
    private System.Threading.Timer timeoutTimer;
    private bool timertimeout;
    
    public TimeoutEvent()
    {
      TimerCallback tc = new TimerCallback(this.TimerCallbackHandler);
      this.timeoutTimer = new Timer(tc, this, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
    }

    public bool WaitOne(int timeout)
    {
      // Reset the timer...
      timeoutTimer.Change(timeout, System.Threading.Timeout.Infinite);
      
      // Clear the timeout flag...
      timertimeout = false;

      // Wait for the event to be signaled...
      responseEvent.WaitOne();
 
      // Disable the timer
      timeoutTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);

      return !timertimeout;
    }

    public void Reset()
    {
      responseEvent.Reset();
    }

    public void Set()
    {
      responseEvent.Set();
    }

    public void TimerCallbackHandler(Object state)
    {
      timertimeout = true;
      responseEvent.Set();
    }

  }
}

⌨️ 快捷键说明

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