// this implements the server/rig part public static void Run() { List <MsgHeader> lCliMsg = new List <MsgHeader>(); _serialPort.PortName = "com" + iCom; _serialPort.DtrEnable = true; // GR needed _serialPort.Open(); _continue = true; Thread serialThread = new Thread(SerialOut); Console.WriteLine("Starting thread SerialOut"); serialThread.Start(); MyStart: oldAvg = 0; startTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; //---listen at the specified IP and port no.--- IPAddress localAdd = IPAddress.Parse(sIP); TcpListener listener = new TcpListener(localAdd, iPort); Console.WriteLine("Listening on ip={0}, port={1} ...", sIP, iPort); listener.Start(); //---incoming client connected--- TcpClient client = listener.AcceptTcpClient(); Console.WriteLine("Client connected with ip={0}", client.Client.RemoteEndPoint.ToString()); //---get the incoming data through a network stream--- NetworkStream nwStream = client.GetStream(); byte[] buffer = new byte[client.ReceiveBufferSize]; int iSrvCounter = 0; while (_continue) { try { long lNowMs = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; //---read incoming stream--- which might contain multiple packets in one int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize); Dictionary <int, MsgHeader> dMH = new Dictionary <int, MsgHeader>(); // the read data may contain multiple msgHeader elements, we process all of them in this loop for (int j = 0; j < bytesRead; j += iSizeMh) { byte[] bufInstance = buffer.Skip(j).Take(iSizeMh).ToArray(); MsgHeader aH = (MsgHeader)InterOp.ByteArrayToStruct(bufInstance, 0, typeof(MsgHeader)); if (!bDisableLogging) { Log2("I: " + Convert.ToInt32(lNowMs - startTime) + " index unsorted=" + aH.clientCounter); } dMH[aH.clientCounter] = aH; } int firstindex = -1; int index = 0; // find the newest client packet, as we reset the counter after 255, need to do a search backwards foreach (KeyValuePair <int, MsgHeader> elem in dMH) { index = elem.Key; do { if ((firstindex < 0) || (firstindex > index)) { firstindex = index; } if (!bDisableLogging) { Log2("I: " + Convert.ToInt32(lNowMs - startTime) + " index=" + index + " firstindex=" + firstindex); } index--; if (index < 0) { index = 255; } } while (dMH.ContainsKey(index)); } index = firstindex; if (!bDisableLogging) { Log2("I: " + Convert.ToInt32(lNowMs - startTime) + " firstindex=" + firstindex); } if (index < 0) // Client disconnected { string sMsg = "Client disconnected."; Console.WriteLine("\n{0}", sMsg); _serialPort.RtsEnable = false; Log2(sMsg); client.Close(); listener.Stop(); waveOut.Stop(); goto MyStart; } // now process all all msgHeader elements stored in the dictionary dMH while (dMH.ContainsKey(index)) { MsgHeader aH = dMH[index]; int clientCounter = (int)aH.clientCounter; int serverCounter = (int)aH.serverCounter; if (!bDisableLogging) { Log2("Server read: " + Convert.ToInt32(lNowMs - startTime) + " " + bytesRead + " clientCounter=" + clientCounter + " bitvector=" + Convert.ToString(aH.bitVector, 2).PadLeft(16, '0') + " serverCounter=" + serverCounter + " lMQ=" + lMQ.Count() + " lNQ=" + lNQ.Count()); } // we sent to the client the serverCounter, which we now get back // we can now calulate a roundtrip time seen on the server side if (dServerTime.ContainsKey(serverCounter)) { long srvMs = dServerTime[serverCounter]; int iPing = Convert.ToInt32(lNowMs - srvMs); CheckPing(iPing); lock (dServerTime) dServerTime.Remove(serverCounter); } // we add the data to be send to the serial port to the queue SerialSend(aH); // add a new server reference number and store the milliseconds since epoch in the dictionary dServerTime aH.serverCounter = Convert.ToByte(iSrvCounter); if (lNQ.Count < iQueueSize - 2) { aH.bitVector = 2; // send queue too small } else if (lNQ.Count > iQueueSize + 2) { aH.bitVector = 3; // send queue too big } else { aH.bitVector = 1; } lock (dServerTime) dServerTime[iSrvCounter] = lNowMs; if (!bDisableLogging) { Log2("Server send: " + Convert.ToInt32(DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - startTime) + " clientCounter=" + clientCounter + " bitvector=" + Convert.ToString(aH.bitVector, 2).PadLeft(16, '0') + " serverCounter=" + serverCounter + " lMQ=" + lMQ.Count() + " lNQ=" + lNQ.Count()); } byte[] bytesToSend = InterOp.StructToByteArray(aH); //---write back the text to the client--- nwStream.Write(bytesToSend, 0, bytesToSend.Length); if (iSrvCounter == 255) { iSrvCounter = 0; } else { iSrvCounter++; } index++; if (index > 255) { index = 0; } } int iWaitMs = _waitMilliSecs - Convert.ToInt32(DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - lNowMs); if (iWaitMs < 0) { iWaitMs = 0; } Thread.Sleep(iWaitMs); } catch (Exception e) { Console.WriteLine("Server exception: {0}", e); _serialPort.RtsEnable = false; client.Close(); listener.Stop(); waveOut.Stop(); goto MyStart; } } _continue = false; serialThread.Join(); _serialPort.Close(); }
public static void NetSendThread() { //---create a TCPClient object at the IP and port no.--- TcpClient client = new TcpClient(sIP, iPort); NetworkStream nwStream = client.GetStream(); Console.WriteLine("Client connected with IP {0}", client.Client.RemoteEndPoint.ToString()); while (_continue) { long ms1 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; // we take over the data to send from the list lMQ into our privat list lNQ lock (lMQ) { lock (lNQ) lNQ.AddRange(lMQ); lMQ.Clear(); } if (lNQ.Count > 100) { Console.WriteLine("Client has a large queue, probably the communication to the server is broken. Giving up."); _continue = false; } while (lNQ.Count > 0) { MsgHeader aHs = lNQ[0]; lNQ.RemoveAt(0); int clientCounter = aHs.clientCounter; int serverCounter; // the client stores a list of reference numbers sent by the server // when the client sends this back to the server, it removes it from the list as done if (lSrvNos.Count > 0) { serverCounter = lSrvNos[0]; lock (lSrvNos) lSrvNos.RemoveAt(0); } else { serverCounter = 0; Log2("Client send: " + Convert.ToInt32(DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - startTime) + " Warning: No Server counter found: " + iSizeMh + " clientCounter=" + clientCounter + " bitVector=" + Convert.ToString(aHs.bitVector, 2).PadLeft(16, '0') + " serverCounter=" + serverCounter + " lMQ=" + lMQ.Count() + " lNQ=" + lNQ.Count()); } aHs.serverCounter = Convert.ToByte(serverCounter); if (!bDisableLogging) { Log2("Client send: " + Convert.ToInt32(DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - startTime) + " " + iSizeMh + " clientCounter=" + clientCounter + " bitVector=" + Convert.ToString(aHs.bitVector, 2).PadLeft(16, '0') + " serverCounter=" + serverCounter + " lMQ=" + lMQ.Count() + " lNQ=" + lNQ.Count()); } byte[] bytesToSend = InterOp.StructToByteArray(aHs); nwStream.Write(bytesToSend, 0, bytesToSend.Length); //System.Console.WriteLine("client.ReceiveBufferSize={0}", client.ReceiveBufferSize); byte[] buffer = new byte[client.ReceiveBufferSize]; //---read incoming stream--- which might contain multiple packets in one int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize); // the read data may contain multiple msgHeader elements, we process all of them in this loop for (int j = 0; j < bytesRead; j += iSizeMh) { byte[] bufInstance = buffer.Skip(j).Take(iSizeMh).ToArray(); MsgHeader aHr = (MsgHeader)InterOp.ByteArrayToStruct(bufInstance, 0, typeof(MsgHeader)); clientCounter = aHr.clientCounter; serverCounter = aHr.serverCounter; short sBitvector = aHr.bitVector; if (sBitvector > 1) { // Rig instance will send a status back to the key, inform user about any problem System.Console.Write('!'); Log2("Rig side reports problem: " + sBitvector); } if (!bDisableLogging) { Log2("Client receive: " + Convert.ToInt32(DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - startTime) + " " + bytesRead + " clientCounter=" + clientCounter + " bitVector=" + Convert.ToString(aHr.bitVector, 2).PadLeft(16, '0') + " serverCounter=" + serverCounter + " lMQ=" + lMQ.Count() + " lNQ=" + lNQ.Count()); } lock (lSrvNos) lSrvNos.Add(serverCounter); if (dCliTimeStamps.ContainsKey(clientCounter)) { long ms = dCliTimeStamps[clientCounter]; lock (dCliTimeStamps) dCliTimeStamps.Remove(clientCounter); int iPing = Convert.ToInt32(DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - ms); if (iPing > 1000) { System.Console.Write('!'); Log2("High ping, " + iPing); } avgPing = CheckPing(iPing); } } } long ms2 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; int delta = Convert.ToInt32(ms2 - ms1); int s = _waitMilliSecs - delta; if (s > 0) { Thread.Sleep(s); } } client.Close(); }
// we send the dit and dahs via the serial port, pin7 to the rig // between the rig and the serial port there is an optocoupler to have galvanic separation of the serial port and the rig public static void SerialOut() { Console.WriteLine("Thread SerialOut"); bool bLastPin7 = false; bool bPin7; while (_continue) { // we take over the data to be sent from the list lMQ into our private list lNQ lock (lMQ) { lock (lNQ) { lNQ.AddRange(lMQ); lMQ.Clear(); } } if (lNQ.Count == 0) { Thread.Sleep(_waitMilliSecs); continue; } if (lNQ.Count < iQueueSize - 2) { System.Console.Write('*'); Log2("lNQ queue too small, " + lNQ.Count); } else if (lNQ.Count > iQueueSize + 2) { System.Console.Write('!'); Log2("lNQ queue too large, " + lNQ.Count); } else if (lMQ.Count > 5) { System.Console.Write('!'); Log2("lMQ queue too large, " + lMQ.Count); } // we are delaying the replay to wipe out small delays on the network between key and rig // in case that the bitVector is zero, and the queue is smaller than 5, we delay a bit // bLast16AllZero = lNQ[lNQ.Count - 1].bitVector == 0; // if (bLast16AllZero && lNQ.Count < iQueueSize) { // Thread.Sleep(_waitMilliSecs); // we will wait here additional 10ms // continue; //} MsgHeader aHs = lNQ[0]; // the bitVector contains 16 bits which we replay in this loop to the output pin, pin7 for (int i = 0; i < 16; i++) { bPin7 = (aHs.bitVector & (1 << i)) != 0; if (!bLastPin7 && bPin7) { _serialPort.RtsEnable = true; bLastPin7 = bPin7; if (bStartAudio) { waveOut.Play(); } Morse.ToOn(); } else if (bLastPin7 && !bPin7) { _serialPort.RtsEnable = false; if (bStartAudio) { waveOut.Stop(); } Morse.ToOff(); bLastPin7 = bPin7; } else if (!bPin7) { Morse.IsOff(); } //int iWait = _waitMilliSecs - Math.Max(0, lNQ.Count - iQueueSize); int iWait = _waitMilliSecs - (lNQ.Count - iQueueSize); // if queue is too small add ms, if queue is too big remove ms if (iWait > 0) { Thread.Sleep(iWait); } /* Using Pin 5 = Ground and Pin 7 RTS out to generate +5, +-0 V output * GR 2020-07-19 tested okay */ } lock (lNQ) lNQ.RemoveAt(0); } _serialPort.RtsEnable = false; }