Telnet Support RS232 or Serial Port?

+1 vote
asked Jun 23, 2010 by userGuest (160 points)
edited Dec 18, 2014

Does this control supports RS232 or Serial Port to Connect to?

commented Jul 5, 2012 by Stefan Koell (270 points)
edited Jul 5, 2012

This would be very helpful if this can be implemented. Users have already asked for such a feature.

commented Jul 5, 2012 by Lukas Pokorny (101,070 points)
edited Jul 5, 2012

Please check out the new answer below for sample code - it is quite easy to add this to your application.

4 Answers

0 votes
answered Dec 18, 2014 by Lukas Pokorny (101,070 points)
edited Dec 18, 2014
 
Best answer

As of Rebex Terminal Emulation 2014 R3, serial port connections are supported!

0 votes
answered Jun 23, 2010 by Lukas Pokorny (101,070 points)
edited Jul 12, 2012

Not yet, but we would like to add this capability to one of the upcoming releases. What kind of device would you like to connect to?

commented Jun 24, 2010 by userGuest (160 points)
A 36110 Mainstreet Newbridge
commented Jun 25, 2010 by Lukas Matyska (54,470 points)
edited Jul 12, 2012

Are you able to connect to the device using PuTTY? If yes, can you send us a working PuTTY configuration of the Serial port? Basically we need to know values shown at this screenshot and other changed default values.

0 votes
answered Jul 5, 2012 by Remco770 (140 points)
edited Dec 18, 2014

Is it possible to add this feature? I'd really like it.

commented Jul 5, 2012 by Lukas Pokorny (101,070 points)
edited Jul 5, 2012

Please check out the new answer below for sample code - you can easily add this feature yourself.

commented Dec 18, 2014 by Lukas Pokorny (101,070 points)
edited Dec 18, 2014

We have just added support for this to Rebex Terminal Emulation 2014 R3.

+1 vote
answered Jul 5, 2012 by Lukas Pokorny (101,070 points)
edited Jul 6, 2012

Even though this is not supported out-of-the box yet, it is quite easy to implement a custom ShellChannel that adds support for terminals running over serial port. All you need is Rebex.Terminal.dll (part of Rebex Telnet and Rebex SSH Shell) and the following code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.IO.Ports;

using Rebex.TerminalEmulation;

namespace Rebex.Net
{
    /// <summary>
    /// Provides methods for communication over Serial port.
    /// </summary>
    public class SerialPortFactory : IShellChannelFactory
    {
        private ILogWriter _logger;
        private SerialPort _port;

        public SerialPortFactory(SerialPort port)
        {
            _port = port;
        }

        /// <summary>
        /// Gets the serial port.
        /// </summary>
        /// <value>A serial port.</value>
        public SerialPort Port
        {
            get { return _port; }
        }

        /// <summary>
        /// Gets or sets the logger used by this object.
        /// </summary>
        /// <value>Logger.</value>
        public ILogWriter LogWriter
        {
            get { return _logger; }
            set { _logger = value; }
        }

        /// <summary>
        /// Starts a virtual terminal session.
        /// </summary>
        /// <returns>Virtual terminal object.</returns>
        public VirtualTerminal StartVirtualTerminal()
        {
            return StartVirtualTerminal(null, SerialPortShellChannel.DefaultTerminalWidth, SerialPortShellChannel.DefaultTerminalHeight);
        }

        /// <summary>
        /// Starts a virtual terminal session.
        /// </summary>
        /// <param name="options">Initial terminal options.</param>
        /// <param name="columns">Horizontal size in character columns.</param>
        /// <param name="rows">Vertical size in character rows.</param>
        /// <returns>Virtual terminal object.</returns>
        public VirtualTerminal StartVirtualTerminal(TerminalOptions options, int columns, int rows)
        {
            VirtualTerminal terminal = new VirtualTerminal(columns, rows);
            if (options != null)
                terminal.Options = options;

            bool ok = false;
            try
            {
                terminal.Bind(this);
                ok = true;
                return terminal;
            }
            finally
            {
                if (!ok)
                    terminal.Dispose();
            }
        }

        ShellChannel IShellChannelFactory.CreateShellChannel(TerminalOptions options, int columns, int rows)
        {
            return new SerialPortShellChannel(this, options, columns, rows);
        }
    }

    internal class SerialPortShellChannel : ShellChannel
    {
        // Object ID
        private static int _nextId;

        public const int DefaultTerminalWidth = 80;
        public const int DefaultTerminalHeight = 25;

        private int _id;
        private readonly ShellChannelOptions _flags;
        private readonly TerminalOptions _terminalOptions; // this can be null !!!
        private int _width, _height;

        private ILogWriter _logger;
        private SerialPort _port;

        internal SerialPortShellChannel(SerialPortFactory factory)
            : this(factory, ShellChannelOptions.Terminal | ShellChannelOptions.Shell, null, -1, -1)
        {
        }

        internal SerialPortShellChannel(SerialPortFactory factory, TerminalOptions options, int width, int height)
            : this(factory, ShellChannelOptions.Terminal | ShellChannelOptions.Shell, options, width, height)
        {
        }

        private SerialPortShellChannel(SerialPortFactory factory, ShellChannelOptions flags, TerminalOptions options, int width, int height)
        {
            _id = Interlocked.Increment(ref _nextId);
            _logger = factory.LogWriter;

            _flags = flags;
            _terminalOptions = options;
            _width = width < 0 ? DefaultTerminalWidth : width;
            _height = height < 0 ? DefaultTerminalHeight : height;

            _port = factory.Port;
            _port.Open();
        }

        public override ShellChannelOptions Options
        {
            get { return _flags; }
        }

        public override int Available
        {
            get { return _port.IsOpen ? _port.BytesToRead : -1; }
        }

        public override bool Connected
        {
            get { return _port.IsOpen; }
        }

        public override int TerminalWidth
        {
            get { return _width; }
        }

        public override int TerminalHeight
        {
            get { return _height; }
        }

        public override ShellChannelState GetConnectionState()
        {
            if (_port.IsOpen)
                return ShellChannelState.Connected;
            else
                return ShellChannelState.NotConnected;
        }

        public override PollResult Poll(int microSeconds)
        {
            if (_port.IsOpen)
                return _port.BytesToRead > 0 ? PollResult.DataAvailable : PollResult.NoData;
            else
                return PollResult.Closed;
        }

        public override int Send(byte[] buffer, int offset, int count)
        {
            if (buffer == null)
                throw new ArgumentNullException("buffer");

            if (count < 0)
                throw new ArgumentOutOfRangeException("count");

            if (offset < 0)
                throw new ArgumentOutOfRangeException("offset");

            if (offset + count > buffer.Length)
                throw new ArgumentException("The sum of offset and count is larger than the buffer length.");

            if (count == 0)
                return 0;

            // \r -> \n
            //int last = offset + count - 1;
            //if (buffer[last] == 13)
            //    buffer[last] = 10;

            lock (_port)
            {
                _port.Write(buffer, offset, count);
            }
            Log(LogLevel.Debug, "Sent {0} byte(s) of data.", count);
            Log(LogLevel.Verbose, "Sent data: ", buffer, offset, count);
            return count;
        }

        public override int Receive(byte[] buffer, int offset, int count)
        {
            if (buffer == null)
                throw new ArgumentNullException("buffer");

            if (count < 0)
                throw new ArgumentOutOfRangeException("count");

            if (offset < 0)
                throw new ArgumentOutOfRangeException("offset");

            if (offset + count > buffer.Length)
                throw new ArgumentException("The sum of offset and count is larger than the buffer length.");

            if (count == 0)
                return 0;

            int n;
            lock (_port)
            {
                n = _port.Read(buffer, offset, count);
            }
            Log(LogLevel.Debug, "Received {0} byte(s) of data.", n);
            Log(LogLevel.Verbose, "Received data: ", buffer, offset, n);
            return n;
        }

        public override void SetTerminalSize(int width, int height)
        {
            _width = width;
            _height = height;
            //Log(LogLevel.Debug, "Set terminal size to {0}x{1}.", width, height);

            // _port.Write();
        }

        public override void Close()
        {
            _port.Close();
        }

        internal void Log(LogLevel level, string message, byte[] buffer, int offset, int count)
        {
            if (_logger != null && _logger.Level <= level)
                _logger.Write(level, typeof(SerialPort), _id, "Info", message, buffer, offset, count);
        }

        internal void Log(LogLevel level, string 
commented Jul 6, 2012 by Stefan Koell (270 points)
edited Jul 6, 2012

Thanks for that, Lukas. I will implement and test the above code ;-) Cheers and thanks for your ultra fast response!

...