static void Connect() { UpdateStatus(); status.Id = 0; server?.Dispose(); controller?.Dispose(); server = null; controller = null; config = null; // Use a background thread to do the connect to avoid stalling UI var connectingThread = new Thread(ConnectThread); connectingThread.Start(); // Spin the foreground thread to collect and throw away any user input while we are connecting. Also allow people to access the service menu if they need to. var inputBuffer = ""; while (config == null) { var input = ReaderHardware.Read(); if (input == "A") { inputBuffer = ""; } else if (input == "B") { if (inputBuffer == ServiceMenuMagicCode) { inputBuffer = ""; EnterServiceMenu(); } else { inputBuffer = ""; } } else { inputBuffer += input; } } inputCleared = true; Draw.Heading(config.Name, status.Warning); Draw.Status(-1, false); Logout(); ClearEntry(); }
static void EnterReaderId() { var draw = true; var inputBuffer = ""; while (true) { if (draw) { Draw.Service($@"Enter Reader Id Using Keypad Reader Id: {inputBuffer} [ENT] Save [ESC] Cancel "); draw = false; } var input = ReaderHardware.Read(); if (input.Length != 1) { continue; } switch (input[0]) { case 'A': return; case 'B': int.TryParse(inputBuffer, out var id); if (id > 0) { status.Id = id; File.WriteAllText("readerid.txt", inputBuffer); } return; default: inputBuffer += input; draw = true; break; } } }
static void EnterServer() { var draw = true; var inputBuffer = ""; var segments = new string[] { "_", "x", "x", "x", "x" }; int currentSegment = 0; while (true) { var complete = $"{segments[0]}.{segments[1]}.{segments[2]}.{segments[3]}:{segments[4]}"; if (draw) { Draw.Service($@"Enter Server Using Keypad Server: {complete} [ENT] Next / Save [ESC] Previous / Cancel "); draw = false; } var input = ReaderHardware.Read(); if (input.Length != 1) { continue; } draw = true; switch (input[0]) { case 'A': inputBuffer = ""; if (segments[currentSegment] != "x" && segments[currentSegment] != "_") { if (currentSegment < 4) { segments[currentSegment + 1] = "x"; } segments[currentSegment] = "_"; } else if (currentSegment > 0) { currentSegment -= 1; segments[currentSegment + 1] = "x"; segments[currentSegment] = "_"; } else { return; } break; case 'B': inputBuffer = ""; if (segments[currentSegment] == "x" && segments[currentSegment] == "_") { segments[currentSegment] = "0"; } if (currentSegment < 4) { currentSegment += 1; segments[currentSegment] = "_"; } else { File.WriteAllText("server.txt", complete); return; } break; default: inputBuffer += input; segments[currentSegment] = inputBuffer; break; } } }
static void EnterServiceMenu() { UpdateStatus(); var draw = true; var trigger = false; while (true) { if (draw) { Draw.MenuOverride = true; Draw.Service($@"Version: {status.Version} Uptime: {status.Uptime} Hardware: {status.Hardware} IP Address: {status.Ip} Reader Id: {status.Id} Server: {status.Server} Controller: {status.Controller} Snapshot: {status.LocalSnapshot} [1] Set Reader Id [2] Set Server [3] Test Cabinet [4] Toggle Trigger [5] Update Reader [6] Reboot Reader [7] Shutdown Reader [8] Exit App [9] Download Snapshot"); draw = false; } var input = ReaderHardware.Read(); if (input.Length != 1) { continue; } switch (input[0]) { case 'A': Draw.MenuOverride = false; Draw.Loading("Reconnecting"); return; case '1': EnterReaderId(); break; case '2': EnterServer(); break; case '3': EnterCabinetMenu(); break; case '4': if (trigger) { trigger = false; ReaderHardware.Logout(); } else { trigger = true; ReaderHardware.Login(); } break; case '5': switch (ReaderHardware.Platform) { case HardwareType.OrangePi: Process.Start("bash", "-c \"cd /tmp; rm -f installOPi.sh; wget https://raw.githubusercontent.com/DanDude0/MilwaukeeMakerspacePiFobReader/master/installOPi.sh; chmod +x installOPi.sh; sudo ./installOPi.sh\""); break; case HardwareType.RaspberryPi: Process.Start("bash", "-c \"cd /tmp; rm -f installRPi.sh; wget https://raw.githubusercontent.com/DanDude0/MilwaukeeMakerspacePiFobReader/master/installRPi.sh; chmod +x installRPi.sh; sudo ./installRPi.sh\""); break; } Process.Start("systemctl", "stop MmsPiW26Interface"); Process.Start("systemctl", "stop MmsPiFobReader"); Environment.Exit(0); break; case '6': Process.Start("reboot"); Process.Start("systemctl", "stop MmsPiW26Interface"); Process.Start("systemctl", "stop MmsPiFobReader"); Environment.Exit(0); break; case '7': Process.Start("shutdown", "-hP 0"); Process.Start("systemctl", "stop MmsPiW26Interface"); Process.Start("systemctl", "stop MmsPiFobReader"); Environment.Exit(0); break; case '8': Process.Start("systemctl", "stop MmsPiFobReader"); Environment.Exit(0); break; case '9': Draw.Loading("Downloading Database Snapshot"); //TODO: If we can talk to the server, push attempt history back up BEFORE we overwrite it. try { server.DownloadSnapshot(); Draw.Service("Snapshot updated"); Thread.Sleep(2000); } catch { Draw.Service("Could not download snapshot"); Thread.Sleep(2000); } UpdateStatus(); break; } draw = true; } }
static void EnterCabinetMenu() { var draw = true; var inputBuffer = ""; if (cabinetItems == null) { Draw.MenuOverride = false; Draw.Fatal("Could not load cabinet items"); Thread.Sleep(2000); return; } Draw.MenuOverride = true; while (true) { if (draw) { var menu = ""; foreach (var item in cabinetItems) { menu += $"[{item.Key}] {item.Value}\n"; } var entry = $"\nSelect a tool: {inputBuffer}"; Draw.Cabinet(menu, entry); draw = false; } var input = ReaderHardware.Read(); if (input.Length != 1) { continue; } switch (input[0]) { case 'A': if (inputBuffer.Length > 0) { inputBuffer = inputBuffer.Substring(0, inputBuffer.Length - 1); } draw = true; break; case 'B': int.TryParse(inputBuffer, out var code); if (cabinetItems.ContainsKey(code)) { var item = cabinetItems[code]; Draw.MenuOverride = false; Draw.Heading(config.Name, status.Warning); Draw.Prompt($"Selected: {item}"); controller.Action(key, item); ReaderHardware.Output(code); Thread.Sleep(1000); ReaderHardware.Output(0); return; } else { inputBuffer = ""; draw = true; } break; default: inputBuffer += input; draw = true; break; } } }
static void Main(string[] args) { ReaderHardware.Initialize(); Draw.Loading(""); var userEntryBuffer = ""; var lastEntry = DateTime.MinValue; var seconds = -1; Connect(); // Main activity loop while (true) { var newSeconds = (int)Math.Floor( (expiration - DateTime.Now).TotalSeconds); if (newSeconds > -5 && newSeconds != seconds) { if (warningBeep) { ReaderHardware.Warn(newSeconds); } Draw.Status(newSeconds); } seconds = newSeconds; // This blocks for 5ms waiting for user input var input = ReaderHardware.Read(); if (!string.IsNullOrEmpty(input)) { inputCleared = false; lastEntry = DateTime.Now; } // We're not logged in if (seconds <= 0) { // Transition from logged in state. if (user != null) { Logout(); } if (!inputCleared && DateTime.Now - lastEntry > new TimeSpan(0, 0, 30)) { ClearEntry(); userEntryBuffer = ""; inputCleared = true; } } // We're Logged in else { if (!inputCleared && DateTime.Now - lastEntry > new TimeSpan(0, 0, 30)) { Draw.User(user); userEntryBuffer = ""; inputCleared = true; } } if (input.Length == 8) { ProcessCommand($"W26#{input}"); userEntryBuffer = ""; } else if (input.Length > 10 && input[0] == 0x2) { // Detect and chop off start/stop bytes from an RS232 reader input = input.Substring(1, 10); ProcessCommand(input); userEntryBuffer = ""; } else if (input.Length == 1) { switch (input[0]) { case 'A': ClearEntry(); userEntryBuffer = ""; break; case 'B': ProcessCommand(userEntryBuffer); userEntryBuffer = ""; break; default: userEntryBuffer += input[0]; var count = userEntryBuffer.Length; if (count > 10) { count = 10; } Draw.Entry("".PadLeft(count, '*')); break; } } else if (input.Length > 0) { Console.WriteLine($"Received input unknown [{input.Length}]: {input} {Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(input))}"); } } }