using System; using System.IO; using System.IO.Ports; using System.Text; using System.Threading; using Microsoft.SPOT; using SWModules; using HWModules; namespace SensorModules { public sealed class BTConsole { public NativeUART IOPort; private MotherBoard motherboard = MotherBoard.Instance; private BTConsole() { IOPort = new NativeUART("BTconsole", QRecordType.BTConsole, processMessage, "COM4", 115200, Parity.None, 8, StopBits.One, 5000, 20, true, 36); } private static BTConsole instance; public static BTConsole Instance { get { instance = instance ?? (instance = new BTConsole()); return instance; } } ~BTConsole() { Debug.Print("CLOSING BTCONSOLE"); } public PressureTable DescendTable { get; set; } public bool IsOpen { get { return IOPort.IsOpen; } } public void init() { if (!IOPort.IsOpen) { IOPort.Open(); } IOPort.DiscardInBuffer(); IOPort.DiscardOutBuffer(); Thread.Sleep(3000); //IOPort.Write(setCommandResponse,0,setCommandResponse.Length); } public void powerUp() { // Check for power before changing if (motherboard.QueryChannelPower(MotherBoard.ChannelNames.BluetoothChannel)) return; motherboard.EnableChannelPower(MotherBoard.ChannelNames.BluetoothChannel); EngrLogger.SendConsoleLine += SendLine; init(); EngrLogger.writeToColumns("Powering up BT Module"); } public void powerDown() { // Check for power before changing if (!motherboard.QueryChannelPower(MotherBoard.ChannelNames.BluetoothChannel)) return; EngrLogger.writeToColumns("Powering down BT Module"); EngrLogger.SendConsoleLine -= SendLine; motherboard.DisableChannelPower(MotherBoard.ChannelNames.BluetoothChannel); } private static StringBuilder sbTemp = new StringBuilder(2048); public void SendLine(StringBuilder sbLineToSend) { IOPort.Write(UTF8Encoding.UTF8.GetBytes(sbLineToSend.ToString()), 0, sbLineToSend.Length); } public void SendLine(byte[] outBytes) { IOPort.Write(outBytes, 0, outBytes.Length); } public void CloseConsolePort() { IOPort.Close(); } private static double simPressure = 0.0; public static bool DirectoryValid { get; set; } public static int uploadEngrFileNum = -1; // Working Arrays private static readonly StringBuilder sbConsoleCommand = new StringBuilder(32); private static StringBuilder sbCommand = new StringBuilder(64); private static StringBuilder sbInBytes = new StringBuilder(256); private static byte[] commandBytes = new byte[64]; // Command to disable command response private static readonly byte[] setCommandResponse = UTF8Encoding.UTF8.GetBytes("ATS10=0\r\n"); public void processConsoleCommand(byte[] consoleCommandMessage) { const byte byteToken = 44; // comma int tokenIndex = -1; double argValue = -1; int crIndex = Array.IndexOf(consoleCommandMessage, 13); //Ignore command if it doesn't have a CR if (crIndex == 0) { sbTemp.Clear(); sbTemp.Append("Received non-CR terminated Console Command: "); sbTemp.Append(SafeEncoding.GetChars(consoleCommandMessage, 0, (Array.IndexOf(consoleCommandMessage, 0) - 1))); EngrLogger.writeToColumns(sbTemp); return; } sbTemp.Clear().Append("Processing Console Command: "); sbTemp.Append(SafeEncoding.GetChars(consoleCommandMessage, 0, crIndex)); EngrLogger.writeToColumns(sbTemp); //Check if the command has an argument tokenIndex = Array.IndexOf(consoleCommandMessage, byteToken); //If it has an argument, process it here if (tokenIndex > 0) { sbTemp.Clear(); sbTemp.Append(SafeEncoding.GetChars(consoleCommandMessage, tokenIndex + 1, (crIndex - tokenIndex - 1))); try { argValue = double.Parse(sbTemp.ToString()); //sbTemp.Clear().Append("Console arg value = "); //sbTemp.Append(argValue); //EngrLogger.writeToColumns(sbTemp); } catch { sbTemp.Clear().Append("[ERROR] parsing console command argument: "); sbTemp.Append(SafeEncoding.GetChars(consoleCommandMessage, 0, (crIndex - 1))); EngrLogger.writeToColumns(sbTemp); return; } sbTemp.Clear(); sbTemp.Append(SafeEncoding.GetChars(consoleCommandMessage, 1, tokenIndex - 1)); switch (sbTemp.ToString().ToUpper()) { case "SIMP": simPressure = argValue; sbTemp.Clear().Append("Sim P = ").Append(simPressure.ToString()); break; case "UPENGR": SV.UploadEngrFile = true; uploadEngrFileNum = (int)argValue; break; case "MAXPROFILES": if (((int)argValue > 0) && ((int)argValue < 200)) { sbTemp.Clear().Append("Setting Max Number of Profiles to: ").Append(((float)argValue).ToString()); EngrLogger.writeToColumns(sbTemp); SV.MaxProfiles = (int)argValue; } else EngrLogger.writeToColumns("MaxProfiles value out of range"); break; case "MISSIONTIMEOUT": if (((int)argValue > 0) && ((int)argValue < 120)) { SV.MissionTimeoutTS = new TimeSpan(0, (int)argValue, 0, 0); SV.MissionTimedOut = false; sbTemp.Clear().Append("Set MissionTimeout hours to: ").Append(SV.MissionTimeoutTS.ToString()); EngrLogger.writeToColumns(sbTemp.ToString()); } else EngrLogger.writeToColumns("MissionTimeout value out of range"); break; case "PARKTIME": if (((int)argValue > 0) && ((int)argValue < (2 * 24 * 3600))) { DescendTable.parkTime = new TimeSpan(0, 0, (int)argValue, 0); sbTemp.Clear().Append("Park time minutes to: ").Append(DescendTable.parkTime.ToString()); EngrLogger.writeToColumns(sbTemp); } else EngrLogger.writeToColumns("ParkTime value out of range"); break; case "PARKPRESSURE": if (((float)argValue > 4) && ((float)argValue < 300)) { sbTemp.Clear().Append("Setting Park Pressure to: ").Append(((float)argValue).ToString()); EngrLogger.writeToColumns(sbTemp); DescendTable.pressure = (float)argValue; } else EngrLogger.writeToColumns("ParkPressure value out of range"); break; } } else //process commands without an argument { sbTemp.Clear(); sbTemp.Append(SafeEncoding.GetChars(consoleCommandMessage, 1, (crIndex - 1))); switch (sbTemp.ToString().ToUpper()) { case "GETDIR": EngrLogger.getDirectory(); DirectoryValid = true; break; case "GO": SV.SurfaceOpsGo = true; break; case "RECOVERYTRUE": SV.ForceRecoveryState = true; SV.ForceRecoveryReason.Clear(); SV.ForceRecoveryReason.Append("[ERROR] RECOVERYTRUE cmd from console"); EngrLogger.Comment(SV.ForceRecoveryReason.ToString()); break; case "RECOVERYFALSE": SV.ForceRecoveryState = false; SV.ForceRecoveryReason.Clear(); SV.ForceRecoveryReason.Append("Console set SV.ForceRecoveryState false"); EngrLogger.Comment(SV.ForceRecoveryReason.ToString()); break; case "STARTDOG": sbTemp.Clear().Append("Starting Watchdog"); EngrLogger.writeToColumns(sbTemp); WatchDog.startWatchdog(); break; case "FAKEMTSBD": NAL_A3LAR.fakeMTSBD(); break; case "SURFACEOPS": sbTemp.Clear().Append("Changing State to SurfaceOps"); EngrLogger.writeToColumns(sbTemp); SV.CurrentState = CPFStates.surfaceOps; SV.DoStateEntry = true; break; case "EXIT": sbTemp.Clear().Append("Console Exit Requested"); EngrLogger.writeToColumns(sbTemp); SV.DoStateEntry = true; SV.CurrentState = CPFStates.exit; break; default: sbTemp.Clear(); sbTemp.Append("Invalid command, try again\r\n"); SendLine(sbTemp); break; } } sbConsoleCommand.Clear(); sbConsoleCommand.Append("NONE"); } public void processMessage(QRecord qRecord) { Debug.Print("Processing..."); processConsoleCommand(qRecord.byteArray); } } }