using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO.Ports; using System.IO; using System.Threading; namespace RadioBroadcaster.Server { static class SerialManager { static bool _continue; static SerialPort _serialPort; /// /// Data is sent at a predetermined rate. As the arduino can only process one piece of data at a time, /// we add each command to the buffer; which will be sent as soon as possible /// static string[] SendBuffer = new string[0]; static int SendBufferSize = 64; static int currentBufferPos = 0; // The current line to send static int lastBufferAddition = -1; // The last position added to within the buffer private static System.Timers.Timer CarouselTimer; private static System.Timers.Timer SendBufferTimer; const string FileName = "PortSelection.txt"; public static void Init() { Thread readThread = new Thread(Read); SendBuffer = new string[SendBufferSize]; _serialPort = new SerialPort(); _serialPort.BaudRate = 9600; SendBufferTimer = new System.Timers.Timer(610); // We tick at the same rate as the arduino. There may be clashing // Due to timing differences, but so long as we always take longer than it takes to process data, we // we will ensure data arrives correctly. Make sure this is delayed while serial gets set-up. // Currently, as the carousel works on a 2 second timer, we can send at least 3 packets of data before // a new one is routinely added. SendBufferTimer.Elapsed += SendBufferTimer_Elapsed; CarouselTimer = new System.Timers.Timer(2000); CarouselTimer.Elapsed += CarouselTimer_Elapsed; string[] AvailablePorts; string s = System.Reflection.Assembly.GetExecutingAssembly().Location; try { AvailablePorts = File.ReadAllText(s.Remove(s.LastIndexOf("\\")) + "\\" + FileName).Replace(Environment.NewLine, "\n").Split('\n'); } catch { AvailablePorts = SerialPort.GetPortNames(); File.WriteAllLines(s.Remove(s.LastIndexOf("\\")) + "\\" + FileName, AvailablePorts); } bool[] removedPorts = new bool[AvailablePorts.Length]; for (int i = 0; i < AvailablePorts.Length; i++) { if (AvailablePorts[i].StartsWith("//")) { removedPorts[i] = true; } else { removedPorts[i] = false; } } _serialPort.PortName = AvailablePorts[Array.IndexOf(removedPorts,false)]; try { _serialPort.Open(); LogManager.Write("Serial port opened successfully"); } catch { LogManager.Write("Couldn't access " + _serialPort.PortName + ", loading first port as a default"); _serialPort.PortName = SerialPort.GetPortNames()[0]; _serialPort.Open(); } _continue = true; readThread.Start(); SendBufferTimer.Start(); Console.Write("Ready to write data to the port"); } static bool SendBufferLock = false; static int waitTicks = 0; /// /// Sends data, if there is any, at every timer tick. Allows a queue of commands /// to be executed without clashing. /// /// /// private static void SendBufferTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if(waitTicks > 5) { if (!SendBufferLock) { SendBufferLock = true; if (SendBuffer[currentBufferPos] != null) { string s = SendBuffer[currentBufferPos].Trim(); if (s == "" || s == null) { } else { LogManager.WriteSerial("\tOut: " + s); _serialPort.WriteLine(s); SendBuffer[currentBufferPos] = ""; if (currentBufferPos >= SendBufferSize - 1) { currentBufferPos = 0; } else { currentBufferPos++; } } } SendBufferLock = false; } } else { waitTicks++; } } static string currentIteration = ""; public static void SetRDSStationName(string setStationName, bool useCarousel = false, bool stopCarousel = false) { if (useCarousel) { LogManager.Write("Starting carousel..."); CarouselTimer.Stop(); if(setStationName.Last() != ' ') // Make sure there is a space between the first and last char { setStationName = setStationName + " "; } currentIteration = setStationName; CarouselTimer.Start(); } else { if (setStationName.Length < 9) { Write("RDSName" + setStationName); } else { Write("RDSName" + setStationName.Remove(8)); } } if (stopCarousel) { } } public static void SetRDSStationData(string data) { Write("RDSData" + data); } public static void SetFrequency(string Frequency) { string temp = Frequency.ToLower(); if (temp.Contains("mhz")) { temp = temp.Remove(temp.IndexOf("mhz")); } temp = temp.Replace(".", ""); temp = temp.Trim(); Write("StatFreq" + temp); } public static void SetTXPower(string power) { string s = power.Trim(); Write("TXpower" + s); } private static void CarouselTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { char one = currentIteration[0]; currentIteration = currentIteration.Remove(0, 1) + one; SetRDSStationName(currentIteration); } /// /// Adds the data to the write queue /// /// static void Write(string message) { if(message.Trim() != "") { lastBufferAddition = lastBufferAddition + 1; if (lastBufferAddition > SendBufferSize -1) { lastBufferAddition = 0; } SendBuffer[lastBufferAddition] = message; } } static void Read() { while (_continue) { try { string message = _serialPort.ReadLine(); LogManager.WriteSerial(message); if (message == "beat") { // We recieved a heartbeat } else if (message.Trim() != "") { Console.WriteLine(message); switch (message.Remove(message.IndexOf(":"))) { case "Freq": break; case "TXPower": break; case "InLevel": break; case "ASQ": break; default: break; } } } catch (TimeoutException) { } } } public static bool carouselContinue = false; public static void RDSStationNameCarousel(string StationName, SerialPort serialPort) { string originalName = StationName; string currentIteration = originalName; carouselContinue = true; while (carouselContinue) { char one = currentIteration[0]; currentIteration = currentIteration.Remove(0, 1) + one; if (currentIteration.Length < 9) { serialPort.WriteLine("RDSName" + currentIteration); } else { serialPort.WriteLine("RDSName" + currentIteration.Remove(8)); } Thread.Sleep(1000); } } } }