static void Main(string[] args) { String localCallSign; String cmd; String loopback; Int32 channel = 0; Int32 baud = 9600; String tmpc; DataLinkProvider dlProvider; DataLinkProvider digi1; DataLinkProvider digi2; Connection.ConnectionParameterBuf conParams; Connection.ConnectionStatus cstat; Connection.ConnectionStatus[] mcstat = new Connection.ConnectionStatus[12]; DataLinkProvider[] testProvider = new DataLinkProvider[12]; Console.Write("Local station callsign-SSID? (e.g. KA1XYZ-5) ? "); localCallSign = Console.ReadLine(); // // Set loopback mode to Y if you are not using a TNC. // Console.Write("Use loopback mode? (y/[n]) "); tmpc = Console.ReadLine(); loopback = tmpc; Console.Write("TNC Channel number? ([0]/1/2) "); tmpc = Console.ReadLine(); if (tmpc.Length > 0) { channel = Convert.ToInt32(Console.ReadLine()); } // // Step 1: Create the low level Com Port that communicates directly // with the TNC // if (loopback.ToUpper().StartsWith("Y")) { // // Use loopback. No data goes out the serial port // tncComPort = new COMPort("COM1", 9600, true); } else { // // No loopback. Use the real TNC // Console.Write("Com Port? (COM1, COM2, etc) "); String comp = Console.ReadLine().ToUpper(); Console.Write("Baud? ([9600],19200, etc) "); tmpc = Console.ReadLine(); if (tmpc.Length > 0) { baud = Convert.ToInt32(tmpc); // (JNW Feb 15) } tncComPort = new COMPort(comp, baud); } Char[] c = { ' ' }; // // Tell the KISS layer if there are any characters to 'escape' in // the data stream. The reason for this is some KISS implementations // (Like the TNC in the Kenwood D710A) actually act upon certain // character sequences even when in KISS mode. // // Example: Escape the 'C' character (needed on TM-D710) // // You can also add escape byte for non printable characters using the // SetEscapedCharList(). In this case, supply a string that contains the // comma separated list of bytes to escape. Example: A string value of: // "03, 0d" will exclude byte valus 0x03 and 0x0d // tncComPort.escapedCharList = "C"; //tncComPort.SetEscapedCharsList("03, 0d"); // // Step 2: Create a TNC channel on top of the COM port. TNCs like // the KPC3+ have one channel (channel 0). Other TNCs like the KAM // Plus have 2 (one for VHF (channel 0) and one for HF (channel 1). The // KISS protocol dictates that TNC Channels MUST be in the range of 0-15. // tncVHFChannel = tncComPort.CreateChannel(channel); // // (Optional) Enable the packet monitor function if we want to // monitor all incoming and outgoing packets. Setting the value // to 'Both' enables queue monitoring as well as file logging of // the packets. (We defined the filename above by setting the static // member: Support.pktLogFile above.) // tncVHFChannel.packetMonitorEnable = TNCChannel.PacketMonitorType.Both; // // Step 3: Create a DataLinkProvider assigning it the desited // local station callsign-ssid. Multiple Data Link Providers \ // are supported, however each must have a unique callsign-ssid. // dlProvider = tncVHFChannel.CreateProvider(localCallSign); digi1 = tncVHFChannel.CreateProvider("RELAY1"); digi1.digipeatEnable = true; digi2 = tncVHFChannel.CreateProvider("RELAY2"); digi2.digipeatEnable = true; // // Note: 3a.1 - 3a-3 are optional steps you would do if you want // to change any of the default connection parameter settings for // this particular connection, like MAXIFrame, MaxWindowsSize, etc. // Unless you are planning to change the defaults, you don't have // to do this and can skip right to step 4. // // // Step 3a.1: (Optional) Create a Connection parameter buf to // use during XID negotiation. // conParams = new Connection.ConnectionParameterBuf(); // // Step 3a.2: (Optional) Make any changes to the parameter values // in the parameter buffer here // //conParams.maxWindowSize = 1; //conParams.maxIFrame = 2; // // Step 3a.3: Create a connection using the connection parameters // specified in the parameter buffer and skip step 4 below. // con = dlProvider.CreateConnection(conParams); for (Int32 i = 0; i < testProvider.Length; i++) { testProvider[i] = tncVHFChannel.CreateProvider("T6EST-" + i.ToString()); mcon[i] = testProvider[i].CreateConnection(conParams); mcon[i].registerStateHandlers.ReportConnectionEvents += new EventHandler <ConnectionEvents>(NotifyConnectionState); mcon[i].registerIndicationHandlers.ReportIndicationEvents += new EventHandler <IndicationEvents>(NotifyIndicationEvents); } // // Step 4: Create the Connection using default parameters // //con = dlProvider.CreateConnection(); // // Register for connection state change notifications, if desired // con.registerStateHandlers.ReportConnectionEvents += new EventHandler <ConnectionEvents>(NotifyConnectionState); // // Register for protocol indication event notifications, if desired // con.registerIndicationHandlers.ReportIndicationEvents += new EventHandler <IndicationEvents>(NotifyIndicationEvents); // // Launch our packet monitor thread. (If we chose to monitor packets // above). // MonitorThread = new Thread(PacketMonitor); MonitorThread.Name = "PacketMonitor Thread"; MonitorThread.Start(); // // Launch the thread the displays the data stream coming back from // the remote station // ReaderThread = new Thread(Reader); ReaderThread.Name = "Reader Thread"; ReaderThread.Start(); // // Create a thread that adds a second DataLinkProvider with a different // callsign that we can perform loopback testing with. We only start // the thread when requested by the command '@listener callsign-ssid'. // You would typically only do this when testing in loopback mode. // // In an applications where you wait for other stations to connect, // you can create a pool of connection threads that would permit // multiple independent incoming connections to your app simultaneously. // ResponderThread = new Thread(Responder); // // Command processing loop // StringBuilder sb = new StringBuilder("Commands:" + CRLF); sb.Append(" @h - this help text" + CRLF); sb.Append(" @listener callsign-ssid - Create a second DataLinkProvider for callsign-ssid" + CRLF); sb.Append(" @con callsign-ssid [digi1] [digi2]" + CRLF); sb.Append(" - Connect to remote station callsign-ssid using optional relays" + CRLF); sb.Append(" @mcon n callsign-ssid - Connect T6EST-n to remote station callsign-ssid" + CRLF); sb.Append(" @xid - Initiate XID negotiation" + CRLF); sb.Append(" @data callsign-ssid text - Send 'text' to calllsign-ssid as a datagram packet" + CRLF); sb.Append(" @test callsign-ssid text - Send a TEST command to callsign-ssid & " + CRLF); sb.Append(" wait 5 seconds for a response" + CRLF); sb.Append(" @disc - Disconnect from the currently connected station" + CRLF); sb.Append(" @mdisc n - Disconnect T6EST-n" + CRLF); sb.Append(" @digi callsign-ssid - Create a digipeater at callsign-ssid" + CRLF); sb.Append(" @bye - Disconnect from the currently connected station & " + CRLF); sb.Append(" and exit the program" + CRLF); sb.Append(" @koff - Send the Exit KISS mode sequence to the TNC" + CRLF); sb.Append(" (other text) - Send as data to the connected station" + CRLF + CRLF); Console.WriteLine(sb.ToString()); while (true && dlProvider.Enabled) { // // Command loop // Console.Write(">>> "); cmd = Console.ReadLine(); if (cmd.StartsWith("@h")) { Console.WriteLine(sb.ToString()); continue; } if (cmd.StartsWith("@xid")) { Console.WriteLine("Initiate XID negotiation with remote. status: " + con.InitiateXID().ToString()); continue; } if (cmd.StartsWith("@test ")) { // // Test command requested // String h = cmd.Substring(6); Int32 q = h.IndexOf(" "); String c1 = h.Substring(0, q); h = h.Substring(q + 1); Byte[] resp = dlProvider.LinkTest(c1, "", "", Encoding.ASCII.GetBytes(h), 5000); String respC = "(Timeout)"; if (resp != null) { respC = Encoding.ASCII.GetString(resp); } Console.WriteLine("Test response: " + respC); continue; } if (cmd.StartsWith("@koff")) { // // Send the Kiss Exit command to the TNC // tncVHFChannel.SetKissModeOff(); continue; } if (cmd.StartsWith("@digi ")) { // // Start a digipeater // String h = cmd.Substring(6); DataLinkProvider dl = tncVHFChannel.CreateProvider(h); dl.digipeatEnable = true; dl.accessControlListType = DataLinkProvider.AccessControlListType.black; dl.AccessControlListAdd("n6prw-3"); continue; } if (cmd.StartsWith("@data ")) { // // Send UI datagram // String h = cmd.Substring(6); Int32 q = h.IndexOf(" "); String c1 = h.Substring(0, q); h = h.Substring(q + 1); dlProvider.SendDatagram(c1, Encoding.ASCII.GetBytes(h), Frame.ProtocolVersion.V22); Console.WriteLine("Datagram Sent: " + h); continue; } if (cmd.StartsWith("@mcon ")) { // // Connect to remote station // String[] h = cmd.Substring(6).Split(c); Int32 m = 0; if (h.Length == 2) { m = Convert.ToInt32(h[0]); mcstat[m] = mcon[m].Connect(h[1]); Console.WriteLine("Connect status: " + mcstat[m].ToString()); } continue; } if (cmd.StartsWith("@con ")) { // // Connect to remote station // cstat = Connection.ConnectionStatus.Busy; String[] h = cmd.Substring(5).Split(c); if (h.Length == 1) { cstat = con.Connect(h[0]); } if (h.Length == 2) { cstat = con.Connect(h[0], h[1]); } if (h.Length == 3) { cstat = con.Connect(h[0], h[1], h[2]); } Console.WriteLine("Connect status: " + cstat.ToString()); continue; } if (cmd.StartsWith("@listener ")) { // // Start the listener we'll use for loopback testing // String h = cmd.Substring(10); responderCallSign = h; if (!ResponderThread.IsAlive) { ResponderThread.Start(); } continue; } if (cmd.StartsWith("@disc")) { // // Disconnect from the remote station // cstat = con.Disconnect(); Console.WriteLine("Disconnected: status: " + cstat.ToString()); continue; } if (cmd.StartsWith("@mdisc ")) { // // Disconnect from the remote station // String[] h = cmd.Substring(7).Split(c); Int32 m = 0; if (h.Length == 1) { m = Convert.ToInt32(h[0]); mcstat[m] = mcon[m].Disconnect(); Console.WriteLine("Disconnected: status: " + mcstat[m].ToString()); } continue; } if (cmd.StartsWith("@exit")) { // // Exit KISS mode // tncVHFChannel.SetKissModeOff(); Console.WriteLine("Kiss mode exited"); break; } if (cmd.StartsWith("@bye")) { // // Disconnect and close the program // cstat = con.Disconnect(); Console.WriteLine("Disconnected: status: " + cstat.ToString()); break; } // everything else is treated as data if (!con.isConnected) { Console.WriteLine("Not connected..."); continue; } else { if (cmd.Length > 0) { con.Send(Encoding.ASCII.GetBytes(cmd + CR)); } else { Console.WriteLine("Nothing to send"); } } } //con.Close(); //dlProvider.Close(); //tncVHFChannel.Close(); // // Time to go. Just shutting down the lower layer is sufficient. // All the upper instances will be shut down as well. // tncComPort.Close(); Console.Write("Press return to exit"); cmd = Console.ReadLine(); }
} // New // Function to open the KISS TNC private bool Open() { bool OpenRet = default; OpenRet = true; string strConfiguration; bool blnInKissStartSequence = false; var strLine = default(string); bool blnOnAir1200 = false; bool blnOnAir9600 = false; strAPSFile = Globals.stcSelectedChannel.TNCConfigurationFile; if (File.Exists(strAPSFile) == false) { Globals.queChannelDisplay.Enqueue("R*** .aps Configuration file not found..."); OpenRet = false; } else { try { strConfiguration = File.ReadAllText(strAPSFile); var objStringReader = new StringReader(strConfiguration); do { try { strLine = objStringReader.ReadLine(); if (string.IsNullOrEmpty(strLine)) { break; } var strCommand = strLine.Split(';'); if (!string.IsNullOrEmpty(strCommand[0].Trim())) { var strTokens = strCommand[0].Trim().Split(' '); var switchExpr = strTokens[0].Trim().ToUpper(); switch (switchExpr) { // These key words define the 1200 and 9600 baud segments case "BEGIN1200B": { blnOnAir1200 = true; blnOnAir9600 = false; break; } case "BEGIN9600B": { blnOnAir9600 = true; blnOnAir1200 = false; break; } case "END1200B": { blnOnAir9600 = false; blnOnAir1200 = false; if (Globals.stcSelectedChannel.TNCOnAirBaud == 1200) { break; } break; } case "END9600B": { blnOnAir9600 = false; blnOnAir1200 = false; if (Globals.stcSelectedChannel.TNCOnAirBaud == 9600) { break; } break; } } if (blnOnAir1200 & Globals.stcSelectedChannel.TNCOnAirBaud == 1200 | blnOnAir9600 & Globals.stcSelectedChannel.TNCOnAirBaud == 9600) { var switchExpr1 = strTokens[0].Trim().ToUpper(); switch (switchExpr1) { case "KISSSTART": { strKissStart = new string[0]; blnInKissStartSequence = true; break; } case "KISSEND": { blnInKissStartSequence = false; break; } case "TXDELAY": { intTXDelay = Convert.ToInt32(strTokens[1]); break; } case "PERSISTANCE": { intPersistance = Convert.ToInt32(strTokens[1]); break; } case "SLOTTIME": { intSlottime = Convert.ToInt32(strTokens[1]); break; } case "FULLDUPLEX": { blnFullDuplex = Convert.ToBoolean(strTokens[1]); break; } case "MAXFRAMESIZE": { intMaxFrameSize = Convert.ToInt32(strTokens[1]); break; } case "MAXFRAMES": { intMaxFrames = Convert.ToInt32(strTokens[1]); break; } case "ACKTIMER": { intACKTimer = Convert.ToInt32(strTokens[1]); break; } case "MAXRETRY": { intMaxRetry = Convert.ToInt32(strTokens[1]); break; } case "POLLTHRESH": { intPollThresh = Convert.ToInt32(strTokens[1]); break; } case "KISSEXIT": { blnExitKiss = Convert.ToBoolean(strTokens[1]); break; } case "ESCAPE": { strEscapeChars = strTokens[1].Trim(); break; } default: { if (blnInKissStartSequence) { Array.Resize(ref strKissStart, strKissStart.Length + 1); strKissStart[strKissStart.Length - 1] = strCommand[0].Trim().ToUpper(); } break; } } } } } catch (Exception ex) { Log.Error("[ModemNativeKiss.Open] " + strLine + Globals.CR + ex.Message); } }while (true); } catch (Exception ex) { Log.Error("[ModemNativeKiss.Open] " + ex.Message); } } if (objSerial != null) { objSerial.Close(); Thread.Sleep(Globals.intComCloseTime); objSerial.Dispose(); objSerial = null; } // Open the serial port... try { objSerial = new SerialPort( Globals.stcSelectedChannel.TNCSerialPort, Convert.ToInt32(Globals.stcSelectedChannel.TNCBaudRate), Parity.None, 8, StopBits.One); objSerial.Handshake = Handshake.None; objSerial.RtsEnable = true; try { objSerial.Open(); } catch { Globals.queChannelDisplay.Enqueue("R*** Failed to open serial port on " + Globals.stcSelectedChannel.TNCSerialPort + ". Port may be in use by another application."); Log.Error("[ClinetNativeKISS.Open] Failed to open serial port on " + Globals.stcSelectedChannel.TNCSerialPort); return(false); } if (objSerial.IsOpen == false) { Globals.queChannelDisplay.Enqueue("R*** Failed to open serial port on " + Globals.stcSelectedChannel.TNCSerialPort + ". Port may be in use by another application."); Log.Error("[ModemNativeKiss.Open] Failed to open serial port on " + Globals.stcSelectedChannel.TNCSerialPort); return(false); } else { Globals.queChannelDisplay.Enqueue("G*** Serial port " + Globals.stcSelectedChannel.TNCSerialPort + " opened"); } } catch (Exception ex) { Log.Error("[ModemNativeKiss.Open] " + ex.Message); return(false); } OpenRet = InitializeKISSTnc(); // initialize the TNC to KISS mode if (OpenRet == false) { Log.Error("[ClientNativeKiss.Open] Failed to Initialize KISS TNC"); enmState = LinkStates.LinkFailed; if (objSerial != null) { objSerial.Close(); Thread.Sleep(Globals.intComCloseTime); objSerial.Dispose(); objSerial = null; } return(false); } else { // All OK so set up Peter's Native KISS DLL try { objKissComPort = new COMPort(objSerial); // Globals.stcSelectedChannel.TNCSerialPort, Convert.ToInt32(Globals.stcSelectedChannel.TNCBaudRate)); // set up the optional escape characters if (!string.IsNullOrEmpty(strEscapeChars)) { objKissComPort.escapedCharList = strEscapeChars; // Escape characters from .aps file } objKissChannel = objKissComPort.CreateChannel(0); // Create TNC Channel 0 objKissDLProvider = objKissChannel.CreateProvider(Globals.SiteCallsign); // Create a DLProvider for the Site Call sign // set up the KISS parameters from default values or as updated from the .aps file objConParam = new Connection.ConnectionParameterBuf(); objConParam.ackTimer = 1000 * intACKTimer; // convert from Sec to ms. objConParam.maxRetry = intMaxRetry; objConParam.maxIFrame = intMaxFrameSize; objConParam.maxWindowSize = intMaxFrames; objConParam.pollThresh = 1000 * intPollThresh; // convert from Sec to ms objKissChannel.SetPersistence(intPersistance); objKissChannel.SetSlotTime(intSlottime); objKissChannel.SetTXDelay(intTXDelay); objKissChannel.SetTXFullDuplex(Convert.ToInt32(blnFullDuplex)); enmState = LinkStates.Initialized; } catch (Exception ex) { Log.Error("[ClientNativeKiss.Open] Call to DLL Error: " + ex.ToString()); return(false); } } // Extended logging added for debugging if (File.Exists(Globals.SiteRootDirectory + @"Log\NativeKISSax25PktLog.log")) { File.Delete(Globals.SiteRootDirectory + @"Log\NativeKISSax25PktLog.log"); } Support.pktLogFile = Globals.SiteRootDirectory + @"Log\NativeKISSax25PktLog.log"; objKissChannel.packetMonitorEnable = TNCChannel.PacketMonitorType.LogFile; return(OpenRet); } // Open