You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 rivejä
5.8 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.IO.Ports;
  5. using System.Windows.Forms;
  6. using GPSDOTimeSync.Devices.Thunderbolt;
  7. using GPSDOTimeSync.TimeProviders;
  8. using GPSDOTimeSync.TimeProviders.Thunderbolt;
  9. using System.Diagnostics;
  10. namespace GPSDOTimeSync {
  11. public partial class FormMain : Form {
  12. private static readonly Dictionary<LogLevel, Color> LOG_LEVEL_TO_COLOR = new Dictionary<LogLevel, Color>() {
  13. { LogLevel.Info, Color.Black },
  14. { LogLevel.Warning, Color.Orange },
  15. { LogLevel.Error, Color.Red }
  16. };
  17. private static readonly Dictionary<string, Func<SerialPort, ITimeProvider>> TIME_PROVIDER_CONSTRUCTORS = new Dictionary<string, Func<SerialPort, ITimeProvider>>() {
  18. {
  19. "Trimble Thunderbolt",
  20. new Func<SerialPort, ITimeProvider>((serialPort) => {
  21. ThunderboltSerialPort thunderboltSerialPort = new ThunderboltSerialPort(serialPort);
  22. ITimeProvider timeProvider = new ThunderboltTimeProvider(thunderboltSerialPort);
  23. return timeProvider;
  24. })
  25. }
  26. };
  27. private int lastSystemTimeUpdate;
  28. private ITimeProvider timeProvider;
  29. public FormMain() {
  30. // Check for admin rights
  31. // If running as admin:
  32. // Ask for COM port with dialog
  33. // Connect to COM port
  34. // When time message received:
  35. // If (time in UTC) AND (last time change was more than $MIN_UPDATE_INTERVAL ago) AND (error is less than $ERROR_THRESHOLD)
  36. // Change system time to GPS time
  37. // Else:
  38. // Display message to tell user to run as admin
  39. // Quit
  40. InitializeComponent();
  41. PopulateDropDowns();
  42. lastSystemTimeUpdate = 0;
  43. statusStrip.Renderer = new TruncatedTextEllipsisRenderer();
  44. latestLogMessage.Text = "";
  45. timeAndDateDisplayUpdate.Start();
  46. }
  47. private void PopulateDropDowns() {
  48. foreach (string portName in SerialPort.GetPortNames()) {
  49. serialPortNames.Items.Add(portName);
  50. }
  51. if (serialPortNames.Items.Count > 0) {
  52. serialPortNames.SelectedIndex = 0;
  53. }
  54. foreach (string deviceName in TIME_PROVIDER_CONSTRUCTORS.Keys) {
  55. deviceNames.Items.Add(deviceName);
  56. }
  57. if (deviceNames.Items.Count > 0) {
  58. deviceNames.SelectedIndex = 0;
  59. }
  60. maximumCorrectionUnit.SelectedIndex = 0;
  61. }
  62. private void AddMessageToLog(string message, LogLevel logLevel) {
  63. latestLogMessage.Text = message;
  64. latestLogMessage.ForeColor = LOG_LEVEL_TO_COLOR[logLevel];
  65. }
  66. private void start_Click(object sender, EventArgs e) {
  67. string serialPortName = (string) serialPortNames.SelectedItem;
  68. string deviceName = (string) deviceNames.SelectedItem;
  69. SerialPort serialPort = new SerialPort(serialPortName);
  70. timeProvider = TIME_PROVIDER_CONSTRUCTORS[deviceName](serialPort);
  71. timeProvider.TimeAvailable += (DateTime dateTime) => {
  72. int minimumUpdateIntervalValue = 0;
  73. Invoke(new Action(() => {
  74. minimumUpdateIntervalValue = (int) minimumUpdateInterval.Value;
  75. }));
  76. if (Environment.TickCount - lastSystemTimeUpdate < minimumUpdateIntervalValue * 1000) {
  77. return;
  78. }
  79. if (maximumCorrectionEnabled.Checked) {
  80. // Positive error means system clock is ahead, negative error means system clock is behind
  81. TimeSpan error = SystemTimeUtils.GetSystemTime().Subtract(dateTime).Duration();
  82. TimeSpan maximumError = new TimeSpan();
  83. int maximumCorrectionValue = (int) maximumCorrection.Value;
  84. string maximumCorrectionUnitString = "";
  85. Invoke(new Action(() => {
  86. maximumCorrectionUnitString = (string) maximumCorrectionUnit.SelectedItem;
  87. }));
  88. if (maximumCorrectionUnitString == "hour(s)") {
  89. maximumError = TimeSpan.FromHours(maximumCorrectionValue);
  90. } else if (maximumCorrectionUnitString == "minute(s)") {
  91. maximumError = TimeSpan.FromMinutes(maximumCorrectionValue);
  92. } else if (maximumCorrectionUnitString == "second(s)") {
  93. maximumError = TimeSpan.FromSeconds(maximumCorrectionValue);
  94. }
  95. if (error >= maximumError) {
  96. Invoke(new Action(() => {
  97. AddMessageToLog("System time error exceeded maximum correction: time not set.", LogLevel.Info);
  98. }));
  99. return;
  100. }
  101. }
  102. SystemTimeUtils.SetSystemTime(dateTime);
  103. Invoke(new Action(() => {
  104. AddMessageToLog(
  105. string.Format(
  106. "System time set to {0}.",
  107. dateTime.ToString("HH:mm:ss dd\\/MM\\/yyyy")
  108. ),
  109. LogLevel.Info
  110. );
  111. }));
  112. lastSystemTimeUpdate = Environment.TickCount;
  113. };
  114. timeProvider.Log += (string message, LogLevel logLevel) => {
  115. Invoke(new Action(() => {
  116. AddMessageToLog(message, logLevel);
  117. }));
  118. };
  119. timeProvider.Start();
  120. AddMessageToLog("Time sync started.", LogLevel.Info);
  121. start.Enabled = false;
  122. stop.Enabled = true;
  123. }
  124. private void stop_Click(object sender, EventArgs e) {
  125. timeProvider.Stop();
  126. AddMessageToLog("Time sync stopped.", LogLevel.Info);
  127. stop.Enabled = false;
  128. start.Enabled = true;
  129. }
  130. private void FormMain_FormClosing(object sender, FormClosingEventArgs e) {
  131. timeProvider?.Stop();
  132. }
  133. private void timeAndDateDisplayUpdate_Tick(object sender, EventArgs e) {
  134. DateTime systemTime = SystemTimeUtils.GetSystemTime();
  135. currentTime.Text = systemTime.ToString("HH:mm:ss");
  136. currentDate.Text = systemTime.ToString("dd\\/MM\\/yyyy");
  137. }
  138. private void maximumCorrectionEnabled_CheckedChanged(object sender, EventArgs e) {
  139. maximumCorrection.Enabled = maximumCorrectionEnabled.Checked;
  140. maximumCorrectionUnit.Enabled = maximumCorrectionEnabled.Checked;
  141. }
  142. }
  143. public class TruncatedTextEllipsisRenderer : ToolStripProfessionalRenderer {
  144. protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) {
  145. if (e.Item is ToolStripStatusLabel) {
  146. TextRenderer.DrawText(e.Graphics, e.Text, e.TextFont, e.TextRectangle, e.TextColor, Color.Transparent, e.TextFormat | TextFormatFlags.EndEllipsis);
  147. } else {
  148. base.OnRenderItemText(e);
  149. }
  150. }
  151. }
  152. }