framelayer.cs

来自「zwave 无线通讯协议 PC controller 控制器源码」· CS 代码 · 共 425 行

CS
425
字号
//////////////////////////////////////////////////////////////////////////////////////////////// 
//
//          #######
//          #   ##    ####   #####    #####  ##  ##   #####
//             ##    ##  ##  ##  ##  ##      ##  ##  ##
//            ##  #  ######  ##  ##   ####   ##  ##   ####
//           ##  ##  ##      ##  ##      ##   #####      ##
//          #######   ####   ##  ##  #####       ##  #####
//                                           #####
//          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.6 $
//          Last Changed:     $Date: 2007/02/15 11:34:47 $
//
//////////////////////////////////////////////////////////////////////////////////////////////
#region Using directives

using System;
using System.Xml;
using System.Threading;
using System.Collections;
using System.Diagnostics;
using System.Resources;
using System.Reflection;
using Zensys.ZWave.Logging;
#endregion

namespace Zensys.ZWave.Communication
{
  /// <summary>
  /// 
  /// </summary>
  public class FrameLayer : IFrameLayer, IDisposable
  {
    private ITransportLayer transportLayer;
    private Thread receiveThread;
    private ThreadPriority receivePriority = ThreadPriority.Highest;
    private IFrameLayerAsyncCallback callbackHandler;
    private bool active;
    private ManualResetEvent threadStarted = new ManualResetEvent(false);
    private System.Threading.Timer retransmissionTimeoutTimer;
    private Stack retransmissionStack = new Stack();
    private const int ACK_WAIT_TIME = 2000; // How long in ms to wait for an ack
    private const int MAX_RETRANSMISSION = 3;
    private FrameReceiveState parserState;
    private DataFrame currentDataFrame;
    private const byte MAX_FRAME_SIZE = 88;
    private const byte MIN_FRAME_SIZE = 3;
    private FrameStatistics stats;
    private ZWaveLogging log = ZWaveLogging.GetInstance("FrameLayer", false);
    private bool disposed;
    private ResourceManager resourceManager = new ResourceManager("ZWave.Properties.Resources", Assembly.GetExecutingAssembly());
    /// <summary>
    /// 
    /// </summary>
    /// <param name="transportLayer"></param>
    /// <param name="connectionString"></param>
    public void Open(ITransportLayer transportLayer, String connectionString)
    {
      if (transportLayer == null)
      {
          throw new ArgumentNullException("transportLayer"); 
      }
    
      retransmissionStack = Stack.Synchronized(retransmissionStack);
      this.transportLayer = transportLayer;
      transportLayer.Open(connectionString);

      this.parserState = FrameReceiveState.FRS_SOF_HUNT;

      stats = new FrameStatistics();

      TimerCallback tc = new TimerCallback(this.ReTransmissionTimeOutCallbackHandler);
      this.retransmissionTimeoutTimer = new Timer(tc, this, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);

      active = true;

      // Start the communication receive thread
      receiveThread = new Thread(new ThreadStart(ReceiveThread));
      receiveThread.Priority = receivePriority;
      receiveThread.Start();
      ////// wait for the thread to actually get spun up
      threadStarted.WaitOne();
    }

    /// <summary>
    /// 
    /// </summary>
    public void Close()
    {
      active = false;
      transportLayer.Close();
      if (retransmissionTimeoutTimer != null) retransmissionTimeoutTimer.Dispose();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="frame"></param>
    /// <returns></returns>
    public bool Write(DataFrame frame)
    {
        try
        {
            log.Write(resourceManager.GetString("Transmitted") + frame.ToString());
            TransmittedDataFrame tdf = new TransmittedDataFrame(frame);
            int bytesWritten = 0;
            lock (this)
            {
                retransmissionStack.Push(tdf);

                // Transmit the frame to the peer...
                byte[] data = frame.GetFrameBuffer();
                bytesWritten = transportLayer.Write(data);
                stats.transmittedFrames++;
                // Reset the retransmission timer...
                retransmissionTimeoutTimer.Change(ACK_WAIT_TIME, System.Threading.Timeout.Infinite);
                return bytesWritten == data.Length;
            }
        }
        catch (ITransportLayerException ITE)
        {
            throw new FrameLayerException("Error in ITransportLayer: " + ITE.Message);
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public void Dispose()
    {
      Dispose(true);
    }

    /// <summary>
    /// 
    /// </summary>
    protected virtual void Dispose(bool disposing)
    {
      if (!disposed)
      {
        // Dispose of resources held by this instance.
        // (This process is not shown here.)
         // Set the sentinel.
        threadStarted.Close();
        retransmissionTimeoutTimer.Dispose();
        disposed = true;

        // Suppress finalization of this disposed instance.
        if (disposing)
        {
          GC.SuppressFinalize(this);
        }
      }
    }

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

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

    /// <summary>
    /// 
    /// </summary>
    /// <param name="enable"></param>
    public void EnableTracing(bool enable)
    {
      log.Enable = enable;
    }
    
    #region Private methods

    private class TransmittedDataFrame
    {
      public TransmittedDataFrame(DataFrame frame)
      {
        this.frame = frame;
      }

      public int retries;
      public DataFrame frame;
    }

    private void ReTransmissionTimeOutCallbackHandler(Object handler)
    {
      log.Write(resourceManager.GetString("Retransmission"));
      CheckRetransmission(true);
    }

    private void TransmitACK()
    {
      log.Write(resourceManager.GetString("TransmitAcknowledge"));
      transportLayer.Write(new byte[] { (byte)DataFrame.HeaderType.Acknowledge });
      lock (stats) { stats.transmittedAcks++; }
    }

    private void TransmitNAK()
    {
      log.Write(resourceManager.GetString("TransmitNoAcknowledge"));
      transportLayer.Write(new byte[] { (byte)DataFrame.HeaderType.NotAcknowledged });
      lock (stats) { stats.transmittedNaks++; }
    }

    private bool CheckRetransmission(bool isretry)
    {
        try
        {
            lock (this)
            {
                if (retransmissionStack.Count > 0)
                {
                    TransmittedDataFrame tdf = (TransmittedDataFrame)retransmissionStack.Peek();
                    log.Write(resourceManager.GetString("CheckRetransmission") + tdf.frame);
                    // Transmit the frame to the peer...
                    transportLayer.Write(tdf.frame.GetFrameBuffer());
                    if (isretry)
                    {
                        lock (stats)
                        {
                            stats.transmittedFrames++;
                            stats.retransmittedFrames++;
                        }

                        // Drop the frame if retried to many times
                        if (++tdf.retries >= MAX_RETRANSMISSION)
                        {
                            retransmissionStack.Pop();
                            lock (stats) { stats.droppedFrames++; }
                        }
                    }
                }

                if (retransmissionStack.Count > 0)
                {
                    retransmissionTimeoutTimer.Change(ACK_WAIT_TIME, System.Threading.Timeout.Infinite);
                }
                else
                {
                    retransmissionTimeoutTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
                }
            } // lock
        }
        catch
        {
          log.Write(resourceManager.GetString("CheckRetransmissionException"));
            throw;
        }
      return true;
    }

    /// <summary>
    /// The Data Frame received will be splitted up into the following states
    /// </summary>
    private enum FrameReceiveState : byte
    {
      FRS_SOF_HUNT    = 0x00,
      FRS_LENGTH      = 0x01,
      FRS_TYPE        = 0x02,
      FRS_COMMAND     = 0x03,
      FRS_DATA        = 0x04,
      FRS_CHECKSUM    = 0x05,
      FRS_RX_TIMEOUT  = 0x06
    }

    private bool ParseRawData(byte buffer)
    {
      switch (parserState)
      {
        case FrameReceiveState.FRS_SOF_HUNT:
          if (DataFrame.HeaderType.StartOfFrame == (DataFrame.HeaderType)buffer)
          {
            parserState = FrameReceiveState.FRS_LENGTH;
          }
          else if (DataFrame.HeaderType.Acknowledge == (DataFrame.HeaderType)buffer)
          {
            // Acknowledge received from peer
            // Remove the last frame from the retransmission stack
            lock (stats) { stats.receivedAcks++; }
            lock (this) { if (retransmissionStack.Count > 0) retransmissionStack.Pop(); }
            log.Write(resourceManager.GetString("ReceivedAcknowledge"));
          }
          else if (DataFrame.HeaderType.NotAcknowledged == (DataFrame.HeaderType)buffer)
          {
            // Not Acknowledge received from peer
            lock (stats) { stats.receivedNaks++; }
            CheckRetransmission(true);
            log.Write(resourceManager.GetString("ReceivedNoAcknowledge"));
          }
          else if  (DataFrame.HeaderType.Can == (DataFrame.HeaderType)buffer)
          {
            // Do noting... just wait for the retransmission timer to kick-in
            // CheckRetransmission(false);
            // CAN frame received - peer dropped a data frame transmitted by us
            log.Write(resourceManager.GetString("ReceivedCancel"));
            lock (stats) { stats.droppedFrames++; }
          }
          break;

        case FrameReceiveState.FRS_LENGTH:
          if (buffer < MIN_FRAME_SIZE || buffer > MAX_FRAME_SIZE) 
          {
            parserState = FrameReceiveState.FRS_SOF_HUNT;
          }
          else
          {
            currentDataFrame = new DataFrame((byte)(buffer-3)); // Payload size is excluding len, type & cmd field
            parserState = FrameReceiveState.FRS_TYPE;
          }
          break;

        case FrameReceiveState.FRS_TYPE:
          currentDataFrame.Type = (DataFrame.FrameType)buffer;
          if( currentDataFrame.Type == DataFrame.FrameType.Request ||
            currentDataFrame.Type == DataFrame.FrameType.Response )
          {
            parserState = FrameReceiveState.FRS_COMMAND;
          }
          else
          {
            parserState = FrameReceiveState.FRS_SOF_HUNT;
          } 
          break;

        case FrameReceiveState.FRS_COMMAND:
          currentDataFrame.Command = (DataFrame.CommandType)buffer;
          if( currentDataFrame.IsPayloadFull() )
            parserState = FrameReceiveState.FRS_CHECKSUM;
          else
            parserState = FrameReceiveState.FRS_DATA;
          break;

        case FrameReceiveState.FRS_DATA:
          if (!currentDataFrame.AddPayload(buffer))
            parserState = FrameReceiveState.FRS_SOF_HUNT;
          else
            if(currentDataFrame.IsPayloadFull())
            parserState = FrameReceiveState.FRS_CHECKSUM;
          break;

        case FrameReceiveState.FRS_CHECKSUM:
          if (currentDataFrame.IsChecksumValid(buffer))
          {
            log.Write(resourceManager.GetString("Received") + currentDataFrame);
            // Frame received successfully -> Send acknowledge (ACK)
            TransmitACK();

            // Call the callbackhandler with the received frame
            callbackHandler.FrameReceived(currentDataFrame);
            lock (stats) { stats.receivedFrames++; }

            CheckRetransmission(true);
          }
          else
          {
            // Frame receive failed -> Send NAK
            TransmitNAK();
          }

          parserState = FrameReceiveState.FRS_SOF_HUNT;
          break;

        case FrameReceiveState.FRS_RX_TIMEOUT:
        default:
          parserState = FrameReceiveState.FRS_SOF_HUNT;
          break;

      }

      return true;
    }

    private void ReceiveThread()
    {
      try
      {
        threadStarted.Set();
        byte[] buffer = new byte[100];

        while (active)
        {
          int bytesRead = transportLayer.Read(buffer);
          for (int i = 0; i < bytesRead; i++)
            if (!ParseRawData(buffer[i])) break;
        }
      }
      catch
      {
        log.Write(resourceManager.GetString("ReceiveThreadException"));
      }
      finally 
      {
        log.Write(resourceManager.GetString("ReceiveThreadId") + Thread.CurrentThread.GetHashCode());
      }
    }

    #endregion
  }
}

⌨️ 快捷键说明

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