public void exileSandwich(Sandwich refSandwich) { sandwiches.Remove(refSandwich); }
public void scanSandwichIDs() { List <COMPort> legitPorts = new List <COMPort>(); ///////////////////////////////////////////////////////////// // Get the ports where the sandwich Arduinos are connected // ///////////////////////////////////////////////////////////// // Combination of https://stackoverflow.com/a/46683622 and https://stackoverflow.com/a/6017027 // Selecting from Win32_PnPEntity returns ALL of plug n play devices (as opposed to Win32_SerialPort); // Adding restriction for Name such as '(COM' narrows down to serial devices ManagementObjectSearcher arduinoSearch = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE Name like '%" + COMDeviceNameFragment_ + "%'"); ManagementObjectCollection arduinoList = arduinoSearch.Get(); if (arduinoList.Count > 0) {// Only proceed if there were any ports to which sandwich Arduinos are connected // Extract the names of the ports where sandwich Arduinos are connected foreach (ManagementObject arduino in arduinoList) { string caption = arduino["Caption"].ToString(); int COMStart = caption.IndexOf("(COM") + 1; // +1 to go past the opening bracket int COMEnd = caption.IndexOf(")", COMStart); string portName = caption.Substring(COMStart, COMEnd - COMStart); // Add this port to the list of legit ports legitPorts.Add(new COMPort(0, portName)); } // Out of all the identified legit ports, identify the ones that are already assigned to any sandwiches for (int i = 0; i < sandwiches.Count; i++) { // Identify which sandwiches are already running (implying that they have a working port) and exclude them from the search if (sandwiches[i].getDAQStatus()) { legitPorts.RemoveAll(x => x.portName == sandwiches[i].getCOMPort()); } } } // Assign the remaining legit ports to the appropriate sandwich class instances // Go in reverse direction because we will be removing ports as we assign them // Remaining ports will be assumed as unassigned for (int i = 0; i < legitPorts.Count; i++) {// Get IDs of the sandwiches and associate them with the COM ports. If an invalid or no response is received, remove that port from the list SerialPort port = new SerialPort(legitPorts[i].portName, Communication.serialBaudRate, Communication.serialParity, Communication.serialDataBits, Communication.serialStopBits); port.Handshake = Communication.serialHandshake; port.Encoding = Communication.serialEncoding; port.ReadTimeout = 100; // Increase this if the sandwiches are not responding quick enough bool commandSent = false; try { port.Open(); // Send a check for connection (SERIAL_CMD_CONNECTION command), which the Arduino would respond // with SERIAL_REPLY_CONNECTION and the sandwich ID. port.Write(string.Format("{0}{1}{2}{3}", Communication.SERIAL_CMD_START, Communication.SERIAL_CMD_CONNECTION, Communication.SERIAL_CMD_END, Communication.SERIAL_CMD_EOL)); // Give time for Arduino to respond System.Threading.Thread.Sleep(20); // Sometimes, the first command may not receive a response. So we send a second time // Clear all serial port buffers (to prepare for the second try) port.DiscardInBuffer(); port.DiscardOutBuffer(); port.Write(string.Format("{0}{1}{2}{3}", Communication.SERIAL_CMD_START, Communication.SERIAL_CMD_CONNECTION, Communication.SERIAL_CMD_END, Communication.SERIAL_CMD_EOL)); // Give time for Arduino to respond System.Threading.Thread.Sleep(50); commandSent = true; } catch (Exception err) { errorLogger_.logUnknownError(err); } if (commandSent) {// If the command was successfully sent, start scraping for the response from Arduino try { // Since we set ReadTimeout to a finite number, ReadTo will return a TimeoutException if no response is received within // that time limit. This is done on purpose because the thread would be blocked forever by ReadLine if ReadTimeout is not a // finite number. If no response is received after the timeout or the response is an invalid format, then we assume // that this port is not occupied by the Arduino controlling a sandwich. string readBuffer = port.ReadTo(Communication.SERIAL_REPLY_EOL); // Check if the start and end of the response have the correct flags if (readBuffer.Substring(0, 1) == Communication.SERIAL_REPLY_START && readBuffer.Substring(readBuffer.Length - 1, 1) == Communication.SERIAL_REPLY_END) { // Now extract the sandwich ID that was sent out by this Arduino int startPos = readBuffer.IndexOf(Communication.SERIAL_REPLY_START); int endPos = readBuffer.LastIndexOf(Communication.SERIAL_REPLY_END); string[] replyFragments = Communication.extractReplyFragments(readBuffer, startPos, endPos); if (replyFragments.Length == 2) {// Sanity check; should have two fragments. One for SERIAL_REPLY_CONNECTION and the other for the sandwich ID try { int sandwichID = Convert.ToInt16(replyFragments[1]); // Assign the port to the sandwich class instance with the same ID that we got from the physical sandwich Arduino Sandwich matchingSandwich = sandwiches.Find(x => x.getSandwichID() == sandwichID); matchingSandwich.setCOMPort(legitPorts[i].portName); } catch (Exception err) {// There was a problem in the conversion process; corrupted message maybe? errorLogger_.logUnknownError(err); } } else {// Somehow, number of parameters is wrong. errorLogger_.logCProgError(ErrorLogger.ERR_PROG_REPLY_CORRUPT, "scanSandwichIDs, SERIAL_REPLY_CONNECTION", readBuffer); } // Finally, clear all serial port buffers and close the port port.DiscardInBuffer(); port.DiscardOutBuffer(); port.Close(); } else {// The response doesn't follow the communication standards; either the message is corrupted or the Arduino is not programmed as a TDT Sandwich controller port.Close(); } } catch (TimeoutException) {// No response from this device; it's probably an Arduino which isn't programmed as a TDT Sandwich controller port.Close(); } } else {// If the command was unsuccessfully sent, close the port // Note that since this could also happen if the port failed to open, we ignore any errors from closing the (unopened) port try { port.Close(); } catch (Exception) { } } } }