// 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; }
// loop for polling the serial pins where our Junkers key is attached // polling is every _waitMilliSecs, currently 10ms public static void Read() { bool pin6_last = false; bool pin8_last = false; int iScanCount = 0; int iClientCount = 0; short sOnOffStates = 0; while (_continue) { try { // query relevant pins on serial port bool pin6 = _serialPort.DsrHolding; bool pin8 = _serialPort.CtsHolding; long lMilliSecs = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; if (bSideSwiper) { pin6 |= pin8; // add the status of Pin8 for SideSwiper } // the designed protocol uses a byte to store 16 polls if (pin6) { sOnOffStates |= (short)(1 << iScanCount); } // when all bits of the byte are set, we send this over to the rig if (iScanCount == 15) { if ((lMQ.Count + lNQ.Count) > 5) { System.Console.Write('*'); // warn user if messages to send to the server queue up Log2("queues too large, lMQ=" + lMQ.Count + ", lNQ=" + lNQ.Count); } // the implemented protocol uses one byte to store a reference created by the client // in our case it has the size of a byte (0..255), the counter is reset to 0 when it hits the boundary // with the client refrence byte (0..255) the epoch time in ms is kept in a dictinoary, // the server will send the client reference unmodified back to the client, and the client can calculate a rounttrip time if (dCliTimeStamps.ContainsKey(iClientCount)) { Log2("Warning: Client time stamp not cleared=" + iClientCount); lock (dCliTimeStamps) dCliTimeStamps.Remove(iClientCount); } lock (dCliTimeStamps) dCliTimeStamps.Add(iClientCount, lMilliSecs); MsgHeader mHs; mHs.serverCounter = 0; mHs.bitVector = sOnOffStates; mHs.clientCounter = Convert.ToByte(iClientCount); // hand over the data stored in the msgHeader structure indirectly to the send thread NetSend(mHs); iScanCount = 0; sOnOffStates = 0; if (iClientCount == 255) { iClientCount = 0; } else { iClientCount++; } } else { iScanCount++; } // capture the case where the last status of the key was up (0) and the new is down (1). if (pin6 && !pin6_last) { //start the listening tone waveOut.Play(); Morse.ToOn(); } else if (!pin6 && pin6_last) // now capture the case where the last status of the key was down (1) and the new is up (0). // stop the listening tone { waveOut.Stop(); Morse.ToOff(); } else if (!pin6) { Morse.IsOff(); } if (pin8 && !pin8_last) { // needs to be implemented, implement keyer functionality } if (!pin8 && pin8_last) { // needs to be implemented, implement keyer functionality } pin6_last = pin6; pin8_last = pin8; } catch (TimeoutException) { } Thread.Sleep(_waitMilliSecs); } }