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 + -
显示快捷键?