Skip to content

Commit

Permalink
使用多媒体定时器提高轮询精度,并优化性能
Browse files Browse the repository at this point in the history
  • Loading branch information
Ning committed Oct 6, 2021
1 parent fbd3a54 commit c36e9b6
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 49 deletions.
71 changes: 22 additions & 49 deletions WpfApp1/DataHandle/DataReciver.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
using Codemasters.F1_2019;
using Codemasters.F1_2020;
using Codemasters.F1_2021;
using System;
using System.Net;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using static F1Tools.TypeFactory;

namespace F1Tools
Expand All @@ -13,26 +8,40 @@ public static class DataReciver
{
private static UdpClient UDP;
private static IPEndPoint IP;
public static Thread RecThread;
public static MicroTimer MicroTimer;
private static int _port = 666;
private static GameVersion _version = GameVersion.F1_2020;

static DataReciver()
{
UDP = new UdpClient(_port);
RecThread = new Thread(Handle);
RecThread.Start();
MicroTimer = new MicroTimer(1, 1);
MicroTimer.OnRunningCallback += MicroTimer_OnRunningCallback;
MicroTimer.Start();
}

private static void MicroTimer_OnRunningCallback(int id, int msg, int user, int param1, int param2)
{
if (UDP.Available <= 0)
return;

var bytes = UDP.Receive(ref IP);
if (bytes.Length > 0)
{
var packet = TypeFactory.GetPacket(bytes, _version);
ReciveEvent?.Invoke(packet);
}
}

public static int Port
{
get => _port;
set
{
Stop();
MicroTimer.Stop();
_port = Port;
UDP = new UdpClient(Port);
Run();
MicroTimer.Start();
}
}

Expand All @@ -42,53 +51,17 @@ public static GameVersion Version
set
{
_version = value;
if (RecThread.ThreadState == ThreadState.Stopped)
Run();
MicroTimer.Start();
}
}

private static void Stop()
{
RecThread.Abort();
}

private static void Run()
{
if (RecThread.ThreadState != (ThreadState.Stopped | ThreadState.Aborted))
RecThread.Abort();

RecThread = new Thread(Handle);
RecThread.Start();
}

public static void Dispose()
{
Stop();
MicroTimer.Dispose();
UDP.Close();
UDP.Dispose();
}

private static void Handle()
{
try
{
while (true)
{
Thread.Sleep(0);
if (UDP.Available <= 0)
continue;

var bytes = UDP.Receive(ref IP);
if (bytes.Length > 0)
{
var packet = TypeFactory.GetPacket(bytes, _version);
ReciveEvent?.Invoke(packet);
}
}
}
catch { }
}

public delegate void ReciverHandler(object packet);
public static event ReciverHandler ReciveEvent;
}
Expand Down
1 change: 1 addition & 0 deletions WpfApp1/F1_2020_Tools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
<Compile Include="Helper\Arc.cs" />
<Compile Include="DataHandle\DataReciver.cs" />
<Compile Include="Helper\Helper.cs" />
<Compile Include="Helper\MicroTimer.cs" />
<Compile Include="Models\VersionModel.cs" />
<Compile Include="Resource1.Designer.cs">
<AutoGen>True</AutoGen>
Expand Down
11 changes: 11 additions & 0 deletions WpfApp1/Helper/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,16 @@ public static bool CheckUpdate()
}
catch { return false; }
}

public static ulong GetCpuID(int idx)
{
ulong cpuid = 0;
if (idx < 0 || idx >= System.Environment.ProcessorCount)
{
idx = 0;
}
cpuid |= 1UL << idx;
return cpuid;
}
}
}
131 changes: 131 additions & 0 deletions WpfApp1/Helper/MicroTimer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using System;
using System.Runtime.InteropServices;

namespace F1Tools
{
public class MicroTimer
{
#region 定时器事件类型
const int TIME_ONESHOT = 0;
const int TIME_PERIODIC = 1;
#endregion

private bool isRunning = false;
/// <summary>
/// 定时器的分辨率(resolution)。单位是毫秒
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct TimerCaps
{
public int periodMin;
public int periodMax;
}
#region winmm.dll API声明
/// <summary>
/// 设置一个媒体定时器(定时器事件类型常用的有2种,0:TIME_ONESHOT,1:TIME_PERIODIC)
/// </summary>
/// <param name="delay">以毫秒指定事件的周期。</param>
/// <param name="resolution">以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms。</param>
/// <param name="callback">指向一个回调函数。(委托实例)</param>
/// <param name="user">存放用户提供的回调数据。</param>
/// <param name="mode">指定定时器事件类型:0->TIME_ONESHOT:uDelay毫秒后只产生一次事件;1->TIME_PERIODIC :每隔delay毫秒周期性地产生事件。</param>
/// <returns>定时器的ID,释放资源的时候需要</returns>
[DllImport("winmm.dll")]
private static extern int timeSetEvent(int delay, int resolution, TimerCallback callback, int user, int mode);
/// <summary>
/// 结束定时器,释放资源
/// </summary>
/// <param name="id">设置定时器返回的ID</param>
/// <returns></returns>
[DllImport("winmm.dll")]
private static extern int timeKillEvent(int id);
/// <summary>
/// 初始化结构体,TimerCaps{periodMin,periodMax}
/// </summary>
/// <param name="caps">TimerCaps</param>
/// <param name="sizeOfTimerCaps">TimerCaps的长度</param>
/// <returns></returns>
[DllImport("winmm.dll")]
private static extern int timeGetDevCaps(ref TimerCaps caps, int sizeOfTimerCaps);
#endregion
public delegate void TimerCallback(int id, int msg, int user, int param1, int param2); // timeSetEvent所对应的回调函数的签名
public event TimerCallback OnRunningCallback;
public event TimerCallback OnStartedCallback;
public event TimerCallback OnStopedCallback;

private TimerCallback m_TimerCallback;
private int timerID;
private TimerCaps caps = new TimerCaps();

public MicroTimer(int dueTime, int period)
{
timeGetDevCaps(ref caps, Marshal.SizeOf(caps));
caps.periodMin = period;
caps.periodMax = dueTime;
isRunning = false;
m_TimerCallback = new TimerCallback(TimerEventCallback);
}

/// <summary>
/// 触发事件
/// </summary>
/// <param name="id"></param>
/// <param name="msg"></param>
/// <param name="user"></param>
/// <param name="param1"></param>
/// <param name="param2"></param>
private void TimerEventCallback(int id, int msg, int user, int param1, int param2)
{
OnRunningCallback?.Invoke(id, msg, user, param1, param2);
}

/// <summary>
/// 启动定时器,回调OnStartedCallback
/// </summary>
public void Start()
{
if (!isRunning)
{
timerID = timeSetEvent(caps.periodMin, caps.periodMin, m_TimerCallback, 0, TIME_PERIODIC); // 间隔性地运行
GC.KeepAlive(m_TimerCallback);
if (timerID == 0)
{
throw new Exception("无法启动计时器");
}
isRunning = true;
//if (isRunning)
//OnStartedCallback?.Invoke(this, EventArgs.Empty);
}
}
/// <summary>
///停止定时器
/// </summary>
public void Stop()
{
if (isRunning)
{
timeKillEvent(timerID);
isRunning = false;
//OnStopedCallback?.Invoke(this, EventArgs.Empty);
Dispose();
}
}
/// <summary>
/// 获取定时器允许状态
/// </summary>
/// <returns></returns>
public bool IsRunning()
{
return isRunning;
}
/// <summary>
/// Dispose
/// </summary>
public void Dispose()
{
if (!timerID.Equals(0))
timeKillEvent(timerID);
GC.SuppressFinalize(this);
}
}
}

0 comments on commit c36e9b6

Please sign in to comment.