+1 vote
by (160 points)
edited

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

by (270 points)
edited

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

by (132k points)
edited

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

4 Answers

0 votes
by (132k points)
edited
 
Best answer

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

0 votes
by (132k points)
edited

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?

by (160 points)
A 36110 Mainstreet Newbridge
by (62.7k points)
edited

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
by (140 points)
edited

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

by (132k points)
edited

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

by (132k points)
edited

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

+1 vote
by (132k points)
edited

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 
by (270 points)
edited

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

...