private static void InitializePorts() { foreach (DataRow dr in mySetting.Tables["tblSettings"].Rows) { //Get serial port settings int id = Convert.ToInt32(dr["fldID"]); string threadName = (string)dr["fldThread"]; string portName = (string)dr["fldPortName"]; int baudRate = Convert.ToInt32(dr["fldBaudRate"]); Parity parity = GetParity(dr["fldParity"]); int dataBits = Convert.ToInt32(dr["fldDataBits"]); StopBits stopbits = GetStopBits(dr["fldStopBits"]); int readTimeout = Convert.ToInt32(dr["fldReadTimeout"]); bool enabled = Convertor.StringToBool((string)dr["fldEnabled"]); bool transferCommands = Convertor.StringToBool((string)dr["fldTransferCommands"]); if (!enabled) { continue; } SerialPortPlus serialPort = new SerialPortPlus(portName, id, baudRate, parity, dataBits, stopbits) { ReadTimeout = readTimeout, TransferCommands = transferCommands }; ports.Add(serialPort); //Initialize the serial port switch (threadName.ToLower()) { case "master": { Thread tr = new Thread(() => MasterThread(serialPort)) { Name = $"Thread{id}_{threadName.ToLower()}" }; threads.Add(tr); break; } case "slave": { Thread tr = new Thread(() => SlaveThread(serialPort)) { Name = $"Thread{id}_{threadName.ToLower()}" }; threads.Add(tr); break; } default: throw new NotImplementedException($"Bad input '{threadName}' for fldThread in Settings.xml"); } } }
private static void OpenPort(SerialPortPlus serialPort) { try { serialPort.Open(); } catch (Exception ex) { Messenger.Enqueue($"Can't open {serialPort.PortName}:" + ex.Message); } }
private static void ClosePort(SerialPortPlus serialPort) { try { Thread.Sleep(50); serialPort.Close(); //Messenger.Enqueue(serialPort.PortName + " closed."); } catch (Exception ex) { Messenger.Enqueue($"Can't close {serialPort.PortName}:" + ex.Message); } }
/// <summary> /// Finds and returns the first serialPort with TransferCommand field enabled /// </summary> /// <returns></returns> private static SerialPortPlus GetPlcPort() { SerialPortPlus output = null; foreach (SerialPortPlus port in ports) { if (port.TransferCommands == true) { output = port; break; } } return(output); }
/// <summary> /// Gets the response message from the buffer and clears the buffer /// </summary> /// <param name="masterLength"></param> /// <param name="slaveLength"></param> /// <returns></returns> private static ResponseResult GetResponseMessage(SerialPortPlus serialPort, Telegram telegram, out byte[] result) { if (telegram.responseLength == 0) { Messenger.Enqueue(StandartMessages.TelegramSkiped(telegram)); result = null; return(ResponseResult.Skiped); } //If the telegrams dictionary is filled, ask for it instead byte[] request = telegram.dictionary.Length > 1 ? telegram.dictionary : telegram.request; List <byte> buffer = GetRawResponse(serialPort, request); //If the first byte in the buffer is not 68 or E5, add 68 in front //if (!((buffer[0] == HexToByte("68")[0]) || (buffer[0] == HexToByte("E5")[0]))) buffer.Insert(0, HexToByte("68")[0]); if (buffer.Count == telegram.responseLength) //correct response { result = buffer.ToArray(); //Check checksum if (Checksum.Check(result)) { //If the checksum is correct, proceed Messenger.Enqueue(StandartMessages.SlaveResponded(serialPort, result, request)); return(ResponseResult.Correct); } else { //Return bad checksum Messenger.Enqueue(StandartMessages.BadChecksum(serialPort, telegram, buffer)); return(ResponseResult.Checksum_Error); } } else if (buffer.Count == 0) //no response { Messenger.Enqueue(StandartMessages.RequestTimeout(serialPort, telegram)); result = null; return(ResponseResult.Timeout); } else //unexpected response { Messenger.Enqueue(StandartMessages.UnexpectedResponse(serialPort, telegram, buffer)); result = buffer.ToArray(); return(ResponseResult.Incorrect); } }
private static List <byte> GetRawResponse(SerialPortPlus serialPort, byte[] request) { List <byte> output = new List <byte>(); Stopwatch stopWatch = new Stopwatch(); //Open port OpenPort(serialPort); //Send request and start timeout timer serialPort.DiscardInBuffer(); stopWatch.Start(); //Send request Respond(serialPort, request); //Get response while (stopWatch.Elapsed.TotalMilliseconds < serialPort.ReadTimeout) { if (serialPort.BytesToRead > 0) { do { //Read and save everything from the buffer byte[] receivedBytes = new byte[serialPort.BytesToRead]; serialPort.Read(receivedBytes, 0, serialPort.BytesToRead); //Save the read bytes into the buffer output.InsertRange(output.Count, receivedBytes); Thread.Sleep(200); } while ((serialPort.BytesToRead > 0) && (stopWatch.Elapsed.TotalMilliseconds < serialPort.ReadTimeout)); stopWatch.Stop(); break; } else { Thread.Sleep(50); } } stopWatch.Stop(); stopWatch = null; //Close port ClosePort(serialPort); return(output); }
private static void MasterThread(SerialPortPlus serialPort) { while (MainThread.IsAlive) { try { //For each telegram for (int i = 0; i < telegrams.Count; i++) { Telegram telegram = telegrams[i]; //If the telegram does not belong to this port, skip if (telegram.PortID != serialPort.ID) { continue; } //Get response byte[] response = null; ResponseResult arResponse = ResponseResult.Unindentified; //Retry until response is correct for (int k = 0; k < 8; k++) { try { lock (serialPort) { arResponse = GetResponseMessage(serialPort, telegram, out response); } //If a correct response is received break the cycle if (arResponse == ResponseResult.Correct) { break; } //Sleep between tries Thread.Sleep(TimeSpan.FromSeconds(sleepTime)); } catch (Exception ex) { Messenger.Enqueue(ex.Message); } } telegram.response = response; //Sleep before sending next request if (i < telegrams.Count - 1) { Thread.Sleep(TimeSpan.FromSeconds(sleepTime)); } } //Update the database DBManager.UpdateDB(serialPort.ID); //Sleep Thread.Sleep(TimeSpan.FromSeconds(cycleTime)); } catch (Exception ex) { Messenger.Enqueue(ex.Message); } } ClosePort(serialPort); }
private static void SlaveThread(SerialPortPlus serialPort) { List <byte> serialBuffer = new List <byte>(); byte[] lastResponse = new byte[0]; //Try to open the port OpenPort(serialPort); //If the port didnt open return if (!serialPort.IsOpen) { return; } //clear the buffer serialPort.DiscardInBuffer(); //Messenger.Enqueue($"{Thread.CurrentThread.Name} status: {Thread.CurrentThread.IsAlive.ToString()}"); while (MainThread.IsAlive) { try { int bytesToRead = serialPort.BytesToRead; //Wait for a full telegram if (serialPort.BytesToRead > 0) { Thread.Sleep(100); if (serialPort.BytesToRead > bytesToRead) { continue; } else { bytesToRead = serialPort.BytesToRead; } } else { Thread.Sleep(250); continue; } //Read and save everything from the buffer byte[] receivedBytes = new byte[bytesToRead]; //Console.WriteLine($"Bytes to read: {receivedBytes.Length}"); serialPort.Read(receivedBytes, 0, bytesToRead); //If the received message is just an echo, ignore it if (echoCancellation && IsEcho(lastResponse, receivedBytes)) { Messenger.Enqueue(StandartMessages.EchoIgnored(serialPort, receivedBytes)); continue; } //Save the read bytes into the buffer serialBuffer.InsertRange(serialBuffer.Count, receivedBytes); //If there are known telegrams to listen for, do so if (telegrams.Count > 0) { //For each telegram in the list for (int i = 0; i < telegrams.Count; i++) { Telegram telegram = telegrams[i]; //If a telegram is recognized if (FindInBuffer(telegram.request, serialBuffer)) { Respond(serialPort, telegram, ref lastResponse); //If the telegram is of the default type clear the buffer, //else keep the bytes and wait for next telegram if (telegram.teleType != TeleType.Complex) { serialBuffer.Clear(); } break; } else if (i >= telegrams.Count - 1) { //Check if any of the master ports have TransferCommand enabled SerialPortPlus sp; if ((sp = GetPlcPort()) != null) { lock (sp) { Messenger.Enqueue(StandartMessages.UnrecognizedTelegram(serialPort, serialBuffer) + $"...sending to {sp.PortName}"); //Send the bytes to the port and get response List <byte> response = GetRawResponse(sp, serialBuffer.ToArray()); byte[] arrResponse = response.ToArray(); Messenger.Enqueue($"[{sp.PortName}]response is: [{Convertor.ByteToHex(arrResponse)}], transfering response to master..."); //Send the responce back to the port that requested it Respond(serialPort, arrResponse); lastResponse = arrResponse; serialBuffer.Clear(); } } else { Messenger.Enqueue(StandartMessages.UnrecognizedTelegram(serialPort, serialBuffer)); serialBuffer.Clear(); } } } } else //Sniff the port { Messenger.Enqueue(StandartMessages.CurrentBytes(serialPort, serialBuffer)); serialBuffer.Clear(); } //Check connection if (!serialPort.IsOpen) { Reconnect(serialPort); } //Sleep between readings Thread.Sleep(250); } catch (Exception ex) { Messenger.Enqueue(ex.Message); serialBuffer.Clear(); serialPort.DiscardInBuffer(); Thread.Sleep(250); } } serialPort.Close(); }