<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mark Nelson &#187; Serial Communications</title>
	<atom:link href="http://marknelson.us/category/serial-communications/feed/" rel="self" type="application/rss+xml" />
	<link>http://marknelson.us</link>
	<description>Programming, mostly.</description>
	<lastBuildDate>Fri, 13 Apr 2012 19:25:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Automating Putty</title>
		<link>http://marknelson.us/2011/12/10/automating-putty/</link>
		<comments>http://marknelson.us/2011/12/10/automating-putty/#comments</comments>
		<pubDate>Sat, 10 Dec 2011 12:11:15 +0000</pubDate>
		<dc:creator>Mark Nelson</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Magazine Articles]]></category>
		<category><![CDATA[Serial Communications]]></category>

		<guid isPermaLink="false">http://marknelson.us/?p=776</guid>
		<description><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2011/12/10/automating-putty/' addthis:title='Automating Putty' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div>Windows users who need a command line connection to another system via telnet or SSH are big fans of PuTTY. It&#8217;s free, it has every feature you need, and it&#8217;s reliable. One thing many people would like to do is use PuTTY as a component in their program. Apparently this comes up so often enough [...]]]></description>
			<content:encoded><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2011/12/10/automating-putty/' addthis:title='Automating Putty' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div><p>Windows users who need a command line connection to another system via telnet or SSH are big fans of <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/" class="newpage">PuTTY</a>. It's free, it has every feature you need, and it's reliable. </p>
<p>One thing many people would like to do is use PuTTY as a component in their program. Apparently this comes up so often enough that there is a <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/faq.html#faq-embedding" class="newpage">FAQ entry</a> dedicated to the topic. Alas, PuTTY does not have any sort of automation interface, so this goal has always been out of reach.</p>
<p>In this article I will show you how to work around this minor shortcoming. Creating a version of PuTTY that can be driven from a Windows program turns out to be an easy task. I'll demonstrate this with a small C++ program that shows exactly how to get this versatile program to do your bidding. My solution works for C++, but the changes I make should work well with any Windows software that can properly process a few messages.<br />
<span id="more-776"></span></p>
<h4>Putting Together the Project</h4>
<p>I'm using Visual Studio 2010 to build both my program and the modified version of Putty. I created the basic outline as follows:</p>
<ol>
<li/>Use the <em>File|New|Project</em> menu item to bring up the list of available project wizards.
<li/>Select <em>MFC project</em>, and enter a project name (I used the uninspired name <em>PuttyDriver</em>.)
<li/>I don't want the default MFC settings, so in the MFC App Wizard, select the <em>Next</em> button.
<li/>On the <em>Application Type</em> page of the wizard, change the Application Type to <em>Dialog Based</em>.
<li/>The project is ready to go at this point, you can click the <em>Finish</em> button and then build your initial project.
</ol>
<p>My driver program is only going to do one thing: direct putty to connect to the host of my choice, then log in using canned credentials. The resulting UI is shown below, and I am going to leave the very minor details of creating it up to the reader.</p>
<table border="0" width="100%">
<tr>
<td><center><img src="/attachments/2011/putty/Figure01.png"></center></td>
</tr>
<tr>
<td><center>The driver program - a simple dialog-based MFC app</center></td>
</tr>
</table>
<h4>Adding Putty to the Project</h4>
<p>The next step in this process is to add the Putty components to the project. I downloaded version 0.61 of the PuTTY source from the <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html" class="newpage">download page</a> and extracted it to a separate folder. I then used Visual Studio's <em>File|Add|Existing Project</em> to add the compatible project file, <code>Putty.dsp</code>, found in <code>/Windows/MSVC/Putty</code>. Visual Studio has to convert this project to a version 10 project file, but it should do so with no problems.</p>
<p>I then right-clicked on the Putty project in Solution Explorer and renamed it to <em>AutoPutty</em>. Since this version of PuTTY will have some slightly different behavior, I don't want to confuse the executable I am creating with the real thing.</p>
<p>From Project|Project Dependencies, I set the PuttyDriver project to depend on AutoPutty - this insures that both projects get built when I build the entire solution.</p>
<p>My final change to the project is to modify the output directory for both Debug and Release versions of AutoPutty. I set the project to build the executable in the root directory of my PuttyDriver project - this will make it easy to find the executable when I need to launch it. I had to make this change in two places: <em>Properties|Configuration Properties|General|Output Directory</em> and <em>Properties|Linker|Outuput File</em>.</p>
<p>When you finally build the project, you'll find that current version of Microsoft's C++ compiler complain quite a bit about the use of functions like <code>strcpy</code> - Microsoft would like you to use safer replacement functions. You may choose to turn those errors off by defining <code>_CRT_SECURE_NO_WARNINGS</code> in the project file. While you are there, you should define <code>SECURITY_WIN32</code> as well - it is required by Windows header <code>sspi.h</code>.</p>
<p>After a successful build you should find a copy of <code>AutoPutty.exe</code> in the root directory of your project, and it should run on your system and behave just like PuTTY.</p>
<h4>Launching AutoPutty</h4>
<p>If I'm going to have a PuTTY component in my PuttyDriver program, one of the first things I need is to be able to start and stop AutoPutty. So my first step in this project is to create the code that launches the program from PuttyDriver. The code below is inserted into the handler for the Start button:</p>
<pre>
UpdateData( true );
char path[MAX_PATH];
GetCurrentDirectory(MAX_PATH, path);
if ( path[ strlen(path) - 1 ] != '\\' )
    strcat_s( path, MAX_PATH, &quot;\\&quot; );
strcat_s( path, MAX_PATH, &quot;AutoPutty.exe -ssh &quot; );
strcat_s( path, MAX_PATH, m_HostName.GetBuffer() );
PROCESS_INFORMATION pi;
ZeroMemory(&amp;pi, sizeof(pi) );
STARTUPINFO si;
ZeroMemory(&amp;si, sizeof(si) );
si.cb = sizeof(si);
if ( CreateProcess( NULL, path, NULL, NULL, NULL, NULL, NULL, NULL, &amp;si, &amp;pi ) )
{
    Sleep( 1000 );
    BringWindowToTop();
}
</pre>
<p>This code assumes that <code>AutoPutty.exe</code> is in the current directory, and launches it with a command line telling it to connect to the host named in the dialog using <a href="http://www.ietf.org/rfc/rfc4251.txt" class="newpage">ssh</a>. Assuming that you have the project set up properly, pushing the start button should now start an independent copy of AutoPutty, which will behave identically to classic PuTTY.</p>
<h4>Taking Ownership of AutoPutty</h4>
<p>At this point I can successfully launch AutoPutty, but I can't really start calling this an integrated part of my main program, PuttyDriver. All I have done is set up a launcher for a separate executable. </p>
<p>The next step in the integration process is to establish PuttyDriver as the owner of AutoPutty's main window. Most Windows programmers are familiar with the traditional parent/child relationship between windows. That relationship is well understood, but I can't use it here - it doesn't work for two top level windows.</p>
<p>Setting PuttyDriver to be the <em>owner</em> (as opposed to the parent) of AutoPutty has the following effects, as explained <a href="http://msdn.microsoft.com/en-us/library/ms632599(v=VS.85).aspx#owned_windows" class="newpage">here</a> by Microsoft:</p>
<ul>
<li/>The owned window will always be above its owner in the z-order.
<li/>The system automatically destroys the owned window when the owner is destroyed.
<li/>The owned window is hidden when the owner is minimized.
</ul>
<p>The most straightforward way to set ownership of the window is to pass the owner's handle in the call to <code>CreateWindow()</code>, which means I will now make my first modifications to the PuTTY source code. </p>
<p>There are a number of ways to pass the owner handle to AutoPutty for use in the call to <code>CreateWindow()</code>, with the most obvious being to pass it on the command line. In the interest of minimizing changes to the existing PuTTY code base, I elected to pass it by creating an environment variable that holds the owner window handle. Since a child process inherits the parent's environment, this is a no-fuss way to get the data to AutoPutty.</p>
<p>I added the following code to the end of <code>InitDialog()</code> in PuttyDriver:</p>
<pre>
CString hwnd_text;
hwnd_text.Format( &quot;%d&quot;, m_hWnd );
SetEnvironmentVariable(&quot;PUTTY_OWNER&quot;, hwnd_text );
</pre>
<p>This sets the environment variable for AutoPutty to find when it gets launched.</p>
<p>Now I come to the point where I am actually making changes to the PuTTY code. Fortunately, all of the changes needed for this program are confined to two files: <code>terminal.c</code> and <code>windows/window.c</code>. My first change is to <code>window.c</code>. This file contains the WndProc for the PuTTY window, and thus most of the rendering and control code for the GUI.</p>
<p>In order to establish the Owner/Owned relationship, I need to modify the code that calls <code>CreateWindow()</code>. I hoisted the function call into a block, added code to get the owner window handle, and inserted the handle into the call to <code>CreateWindow()</code>:</p>
<pre>
{
    HWND owner_hwnd = 0;
    char buffer[ 132 ];
    if ( GetEnvironmentVariable( &quot;PUTTY_OWNER&quot;, buffer, 132 ) )
        sscanf( buffer, &quot;%d&quot;, &amp;owner_hwnd );
    if ( owner_hwnd == 0 )
        MessageBox( NULL,
                    &quot;AutoPutty did not find the handle for the &quot;
                    &quot;owner window, this is not going to work&quot;,
                    &quot;Fail&quot;,
                    MB_OK );
    hwnd = CreateWindowEx(exwinmode, appname, appname,
                          winmode, CW_USEDEFAULT, CW_USEDEFAULT,
                          guess_width, guess_height,
                          owner_hwnd, NULL, inst, NULL);
}
</pre>
<p>At this point I've only modified one small block of code in the PuTTY source, but I'm well on my way to having it behave more like a component of PuttyDriver and less like an independent program. The ownership status means that the two programs only appear once on the taskbar, and will only appear once when you are pressing ALT-TAB to select a new active process. And they only produce a single entry in the Applications Tab of Task Manager.</p>
<h4>The Communications Link</h4>
<p>In order to achieve the automation that I am seeking, I also need to have two way communications between AutoPutty and the driver program. Since this is Windows, a natural choice for communications is to use native Windows messages. In order to do this, both programs need the Window handle of their opposite number.</p>
<p>I've already solved half of that problem through the ownership relationship established when I created the main window for AutoPutty. Now that it has set PuttyDriver as its owner window, I can get this window handle any place in the program through a simple function call:</p>
<pre>
HWND parent = GetWindow(hwnd, GW_OWNER);
</pre>
<p>But the reverse is not true - PuttyDriver does not know have a copy of the window handle for AutoPutty. </p>
<p>To remedy this situation, I added code to <code>window.c</code> that notifies its owner when it s created, and when it is destroyed. First I add this statement immediately after the call to <code>CreateWindow()</code>:</p>
<pre>
if ( owner_hwnd )
   PostMessage( owner_hwnd, WM_APP, 0, (LPARAM) hwnd );
</pre>
<p>This tells PuttyDriver that the window is created, and gives it the handle to use for communications.</p>
<p>I also need to know when the window is closed, and I have to add that code two places in <code>window.c</code> - because Putty can be shut down two different ways. </p>
<p>Normally AutoPutty will shut down in response to a windows message. When this happens, I can count on a <code>WM_CLOSE</code> message being sent to the Windows Procedure. I add this code the existing handler for <code>WM_CLOSE</code>:</p>
<pre>
if (!cfg.warn_on_close || session_closed ||
    MessageBox(hwnd,
               &quot;Are you sure you want to close this session?&quot;,
               str, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1)
    == IDOK) {
    HWND parent = GetWindow(hwnd, GW_OWNER);
    if ( parent )
        SendMessage( parent, WM_APP, 0, 0 );
    DestroyWindow(hwnd);
}
</pre>
<p>This lets PuttyDriver know that the window has been destroyed.</p>
<p>The original PuTTY code has an alternative method of shutdown. When it receives one of several possible network events, such as a telnet connection being broken, it calls <code>PostQuitMessage()</code>. When a program shuts down this way, it doesn't issue messages to destroys its windows - it relies on the O/S to destroy the windows when the process exists. As a result, I have to make a change in <code>WinMain()</code>, the main window procedure for PuTTY. This procedure extracts the messages sent to it using <code>PeekMessage</code>, and I add some code to handle the processing when a <code>WM_QUIT</code> message is sent:</p>
<pre>
if (msg.message == WM_QUIT) {
    HWND parent = GetWindow(hwnd, GW_OWNER);
    if ( parent )
        SendMessage( parent, WM_APP, 0, 0 );
    goto finished;	       /* two-level break */
}
</pre>
<h4>Handling the AutoPutty Lifecycle Events</h4>
<p>To keep track of the state of AutoPutty, I have to add a handler for <code>WM_APP</code> to PuttyDriver. It does two things when handling the incoming<code> WM_APP</code> event.</p>
<p>First, then handler stores the handle of the AutoPutty window - or sets the value to 0 when the window has been destroyed.</p>
<p>Second, it either enables or disables the button used to start up AutoPutty. Since this program can only manage one window at a time, I don't want to allow any inadvertent button pushes:</p>
<pre>
afx_msg LRESULT CPuttyDriverDlg::OnWmApp(WPARAM wParam, LPARAM lParam)
{
    m_PuttyWindow = (HWND) lParam;
    m_StartButton.EnableWindow( !m_PuttyWindow );
    return 0;
}
</pre>
<p>One final piece of bookkeeping is to make sure that the AutoPutty window is shut down when PuttyDriver shuts down. (The Windows documentation claims this happens automatically to owned windows, but it doesn't seem to be the case.)</p>
<pre>
void CPuttyDriverDlg::OnDestroy()
{
    CDialogEx::OnDestroy();
    if ( m_PuttyWindow )
        ::SendMessage( m_PuttyWindow, WM_CLOSE, 0, 0 );
}
</pre>
<h4>Monitoring Input Traffic</h4>
<p>Now that I have control over the lifetime of my AutoPutty window, it's time to take the next step in automation. My driver program needs to watch all the data coming in from the remote end so that it can take action on various types of input.</p>
<p>Depending on how you set up your connection, PuTTY can receive input data from a serial port, a Telnet connection, or an SSH connection. Fortunately the Windows version of PuTTY uses a standard handle-based interface to all three types of connections. The routine <code>term_data()</code> in <code>terminal.c</code> is called as data arrives, regardless of the source.</p>
<p>Since we are using the Windows API to communicate between processes, it makes sense to use the <code>WM_COPYDATA</code> message to send data to the parent program as it arrives. <code>WM_COPYDATA</code> is a good choice, as it takes care of marshalling the data between the two processes, which can add some complication to other solutions. The modified routine is shown below:</p>
<pre>
int term_data(Terminal *term, int is_stderr, const char *data, int len)
{
    HWND parent = GetWindow(hwnd, GW_OWNER);
    if ( parent ) {
        COPYDATASTRUCT cd;
        cd.dwData = (ULONG_PTR) 0xDEADBEEF;
        cd.cbData = len;
        cd.lpData = (PVOID) data;
        SendMessage( parent, WM_COPYDATA, (WPARAM) hwnd, (LPARAM) &amp;cd );
    }
</pre>
<h4>Receiving the Data</h4>
<p>To receive this messages in PuttyDriver, I simply create a handler for <code>WM_COPYDATA</code> and start grabbing the data as it arrives. One important thing to note is that because AutoPutty has to use <code>SendMessage()</code> to send the data to its parent, it has to wait for PuttyDriver to finish processing the data until it can continue. This dictates a certain style of behavior on my part.</p>
<p>There are quite a few ways to skin this cat, and I'm keeping it very simple here. I'm using a <code>deque&lt;char&gt;</code> container to hold the last 64 characters I've received. After each <code>WM_COPYDATA</code> message I received, I check to see if the current output snapshot ends in one of my trigger messages. If it does, I post the message number to myself for later processing, then return so that AutoPutty can continue its work.</p>
<p>The code I'm using here is doing something fairly simple: automating the login process by using the credentials that I've entered into the dialog box. That means the two strings I'm looking for are the login and password prompts. The resulting code is shown here:</p>
<pre>
BOOL CPuttyDriverDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
    char *p = (char *) pCopyDataStruct-&gt;lpData;
    int len = pCopyDataStruct-&gt;cbData;
    if ( len &gt;= 64 ) {
        p += len - 64;
        len = 64;
        m_Snapshot.clear();
    }
    while ( len-- )
        m_Snapshot.push_front(*p++);
    m_Snapshot.resize(64);
    static const char *needles[2] = { &quot;login as: &quot;, &quot;password: &quot; };
    for ( int i = 0 ; i &lt; 2 ; i++ ) {
        int len = strlen( needles[i] );
        int j;
        for ( j = 0 ; j &lt; len ; j++ ) {
            if ( needles[i][j] != m_Snapshot[len-1-j] )
                break;
        }
        if ( j == len )
            PostMessage( WM_APP+1, i, 0 );
    }
    return TRUE;
}
</pre>
<p>There is plenty of room for improvement in this routine, much of it depending on what type of automation you are going to be using in your program. Some obvious items would include the ability to add and remove triggers as the program progresses, and regular expression matching for triggers. </p>
<h4>Driving PuTTY</h4>
<p>This login program is now complete save for one detail: I need a way to send my responses back to AutoPutty. </p>
<p>The first part of this is pretty obvious - I just need to read the data from the dialog box and post it to AutoPutty with my useful <code>WM_COPYDATA</code> command. This happens in my <code>WM_APP+1</code> handler:</p>
<pre>
afx_msg LRESULT CPuttyDriverDlg::OnWmAppPlusOne(WPARAM wParam, LPARAM lParam)
{
    UpdateData(TRUE);
    CString msg;
    switch ( wParam ) {
    case 0 :
        msg = this-&gt;m_UserId + '\r'; break;
    case 1:
        msg = this-&gt;m_Password + '\r'; break;
    }
    if ( this-&gt;m_PuttyWindow ) {
        COPYDATASTRUCT cd;
        cd.dwData = (ULONG_PTR) 0xF00DFACE;
        cd.cbData = msg.GetLength();
        cd.lpData = (PVOID) (const char *) msg;
        ::SendMessage( this-&gt;m_PuttyWindow,
                       WM_COPYDATA,
                       (WPARAM) this-&gt;m_hWnd,
                       (LPARAM) &amp;cd );
    }
    return 0;
}
</pre>
<p>Sending this data to AutoPutty is fine, but right now the program doesn't do anything with that message. The final piece of work is to add a <code>WM_COPYDATA</code> handler to window.c. </p>
<p>Simply grabbing the data is easy enough - the data structure that accompanies the message contains a pointer to the data and a value indicating its length. However, I have two problems I have to solve before the data is actually sent out to the to whatever device AutoPutty is connected to.</p>
<p>First, I have to take into account the fact that PuTTY was written to use wide characters. My driver program was built using MultiByte characters, so we have a mismatch. This means I have to do a conversion of the data from one domain to the other. This is a two step process - I call <code>MultiByteToWideChar()</code> once to determine how much space I need, then I allocate a buffer and call it again.</p>
<p>The second thing I need to do is determine what to do with the data once I've converted it. PuTTY takes all terminal input and eventually passes through a function called <code>luni_send()</code>. Calling this function directly from the Windows procedure seems to work just fine. </p>
<p>The <code>WM_COPYDATA</code> handler I created looks like this:</p>
<pre>
case WM_COPYDATA :
{
    COPYDATASTRUCT *cd = (COPYDATASTRUCT *) lParam;
    int wsize = MultiByteToWideChar( CP_ACP,
                                     MB_PRECOMPOSED,
                                     (LPCSTR) cd-&gt;lpData,
                                     cd-&gt;dwData,
                                     NULL,
                                     0 );
    wchar_t *buf = (wchar_t *) calloc( wsize+1, sizeof(wchar_t) );
    MultiByteToWideChar( CP_ACP,
                         MB_PRECOMPOSED,
                         (LPCSTR) cd-&gt;lpData,
                         cd-&gt;dwData,
                         buf,
                         wsize + 1 );
    if (term-&gt;ldisc)
        luni_send(term-&gt;ldisc, buf, wsize, 0);
    free( buf );
}
</pre>
<p>At this point I have a working program - it connects to my designated <a href="http://www.webhostingsearch.com/" class="newpage">host</a>, and sends the username and password of my choice to the host, connecting me to the system.</p>
<p>I should add a note of caution here. Automating logins is a tempting time saver, but in general this is a really bad idea. Any time you hard code credentials into a program, you open the door to all sorts of new attacks on your system.</p>
<p>In my demo program, the user has to enter a name and password, so nothing is hardcoded, but even this adds security holes to a system. I encourage you to think of this as a demonstration only.</p>
<p><center></p>
<table border="0">
<tr>
<td><center><iframe width="500" height="281" src="http://www.youtube.com/embed/3O4t9KzpKbo?fs=1&#038;feature=oembed" frameborder="0" allowfullscreen></iframe></center></td>
</tr>
<tr>
<td><center>Demo of the program in action<br/>For a better view, go to full screen and select 720p</td>
</tr>
</table>
<p></center></p>
<h4>Source Code</h4>
<p>I've included the complete source code for PuttyDriver, the MFC project that controls AutoPutty. It was built with Visual Studio 2010, so you may have a little work to do if you backport it to earlier versions. My use of language features and classes should be compatible with much earlier versions - this is all very simple code.</p>
<p>Because PuTTY is always changing, I am not redistributing a snapshot of the version I used. Instead, I'm including before and after copies of the two source files I modified: <code>window.c</code> and <code>terminal.c</code>. If you build with Putty 0.61, you should be able to drop these two files right on top of the files included with the distribution and be on your way. With later versions of PuTTY you will have to perform an intelligent merge of the changes, which I hope will be a fairly effortless process.</p>
<h4>Downloads</h4>
<ul>
<li><a href="/attachments/2011/putty/PuttyDriver.zip">PuttyDriver.zip</a>. The PuttyDriver source and project. You will need to add the PuTTY project to this solution as described in the article.
<li><a href="/attachments/2011/putty/putty.zip">putty.zip</a>. This contains the two PuTTY source files modified for this project. Both the original 0.61 source and my modified source are supplied. Executables are supplied as well, which may or may not work on your system.
</ul>
]]></content:encoded>
			<wfw:commentRss>http://marknelson.us/2011/12/10/automating-putty/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Any Serial Port</title>
		<link>http://marknelson.us/2010/11/07/any-serial-port/</link>
		<comments>http://marknelson.us/2010/11/07/any-serial-port/#comments</comments>
		<pubDate>Sun, 07 Nov 2010 22:50:38 +0000</pubDate>
		<dc:creator>Mark Nelson</dc:creator>
				<category><![CDATA[Serial Communications]]></category>

		<guid isPermaLink="false">http://marknelson.us/2010/11/07/any-serial-port/</guid>
		<description><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2010/11/07/any-serial-port/' addthis:title='Any Serial Port' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div>I spent a pretty big chunk of the 80's and 90's toiling away on Greenl af Commlib, a C/C++ library that provided support for RS-232 communications on MS-DOS and Windows machines. Despite the fact that serial communications ports were standard issue on IBM-compatible PCs, Microsoft provide little or no support for their use under MS-DOS [...]]]></description>
			<content:encoded><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2010/11/07/any-serial-port/' addthis:title='Any Serial Port' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div><p>I spent a pretty big chunk of the 80's and 90's toiling away on <a href="http://www.greenleafsoft.com/CommLib/CommLibSummary.asp" class="newpage">Greenl af Commlib</a>, a C/C++ library that provided support for RS-232 communications on MS-DOS and Windows machines. Despite the fact that serial communications ports were standard issue on IBM-compatible PCs, Microsoft provide little or no support for their use under MS-DOS or 16-bit versions of Windows.  Which allowed Greenleaf to carve out a healthy little business, taking me along with them.</p>
<p>Even with our library, working with RS-232 ports could be pretty tough. C/C++ programmers in this environment didn't have good options for writing code that dealt with asynchronous events, so programs tended to be difficult to both develop and maintain. We tried a lot of approaches to improving the situation, but one thing we never pursued was the idea of developing a <a href="http://en.wikipedia.org/wiki/Domain-specific_language" class="newpage">Domain-specific Language</a>.</p>
<p>In retrospect, I think we might have missed a real opportunity here. A couple of weeks ago I received an email from Orhan Alby, announcing the launch of <a href="http://www.anyserialport.com/" class="newpage">Any Serial Port</a>, a language specifically devoted to developing RS-232 applications. Having a language dedicated to RS-232 programming is a big plus, but Alby took it one step further by providing an IDE that really makes it easy to debug the entire process.</p>
<p>The language is nicely crafted for this kind of work - at the high level it takes the approach of developing a state machine, which is driven by RS-232 events. It's a very natural paradigm for communications work.</p>
<p>Fortunately, the entire project is available on SourceForge under GPLv3. Next time you have a need to dust off your RS-232 knowledge, I encourage you to give a try to Any Serial Port and see if it cuts your development time down. And if you like it, dig in and help improve it!</p>
]]></content:encoded>
			<wfw:commentRss>http://marknelson.us/2010/11/07/any-serial-port/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What to Do When You&#8217;re Past COM2</title>
		<link>http://marknelson.us/1991/04/01/what-to-do-when-youre-past-com2/</link>
		<comments>http://marknelson.us/1991/04/01/what-to-do-when-youre-past-com2/#comments</comments>
		<pubDate>Mon, 01 Apr 1991 14:40:02 +0000</pubDate>
		<dc:creator>Mark Nelson</dc:creator>
				<category><![CDATA[Magazine Articles]]></category>
		<category><![CDATA[Serial Communications]]></category>

		<guid isPermaLink="false">http://test.kewby.com/?p=7</guid>
		<description><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/1991/04/01/what-to-do-when-youre-past-com2/' addthis:title='What to Do When You&#8217;re Past COM2' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div>An article on using Multiport RS-232 boards in C programs.]]></description>
			<content:encoded><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/1991/04/01/what-to-do-when-youre-past-com2/' addthis:title='What to Do When You&#8217;re Past COM2' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div><p>In the mini and microcomputer world, RS-232 links provide what is likely the most heavily used form of communications. RS-232 is versatile and relatively inexpensive. It is possible to connect computers that are considered otherwise to be completely incompatible. RS-232 is also used by computers to talk to devices such as modems, dumb terminals, bar code readers, printers, lab equipment, and more. So it made sense that IBM defined a standard RS-232 interface card for their PC. Up to two of the cards could be installed in a PC, and were referred to as COM1 and COM2.</p>
<p>Unfortunately, each COM card installed in a PC needed its own interrupt line. The original IBM PC had only eight interrupt lines, of which just two were available for use by RS-232 ports. Some third party COM cards could be configured to operate at other addresses on other interrupt lines, so it was in theory possible to operate three ports at once, but this required using interrupt lines that were allocated for other devices. And a user who wanted to operate as many as 8 RS-232 ports simultaneously was essentially out of luck.</p>
<p>The solution to this problem comes in the form of the Multiple Port Shared Interrupt (Multiport) board. These are boards that are set up so that multiple communication ports can share a single interrupt on the PC bus. This article discusses how the programmer can use these boards in MS-DOS applications.<br />
What is a Multiple Port Shared Interrupt Board?</p>
<p>There is no such thing as a standard Multiport RS-232 board. There are many different manufacturers of these boards, and each of them has implemented their board in a different fashion. However, most of the boards have enough in common so that the same programming techniques, and even the same code, can be used to operate them.</p>
<p>The boards discussed in this article all have several things in common. First of all, each of them uses a Universal Asynchronous Receiver/Transmitter (UART) for the 8250 family. The 8250 family of UARTs include the 8250, 16450, and 16550 manufactured by National Semiconductor. These are the same UARTs used by IBM in the standard COM1 and COM2. This means that the actual programming of the registers on the UART of a Multiport board can be done using essentially the same code as already exists for standard RS-232 ports. Most of the boards support 4 or 8 UARTs on a single board, although there are some 16 port boards available.</p>
<p>In addition, the manufacturers of multiport boards all support the same I/O pins used on the IBM PC COM1 and COM2. These are:</p>
<table border="0">
<tr>
<td width="10%">TX</td>
<td>RS-232 transmission</td>
</tr>
<tr>
<td>RX</td>
<td>RS-232 reception</td>
</tr>
<tr>
<td>RTS</td>
<td>Request to Send</td>
</tr>
<tr>
<td>CTS</td>
<td>Clear To Send</td>
</tr>
<tr>
<td>DTR</td>
<td>Data Terminal Ready</td>
</tr>
<tr>
<td>DSR</td>
<td>Data Set Ready</td>
</tr>
<tr>
<td>CD</td>
<td>Carrier Detect</td>
</tr>
<tr>
<td>RI</td>
<td>Ring Indicator</td>
<tr>
</table>
<p>The Multiport board designers use various techniques to bring these signal lines out to multiple 9 or 25 pin D connectors. The DB-25 connector is an industry standard, but IBM began using a nine pin connector as an alternative when the AT series was introduced. For the most part, the board manufacturers seem to be adhering to the 25 pin standard. The nine pin connector used by IBM may have been implemented to save space on a card edge for more connectors, but the multiport vendors don't attempt to mount their connectors on the card edge anyway, so geographical considerations are of less importance.</p>
<p>What makes a Multiport board work on a PC is the shared interrupt logic. This is special hardware that takes the interrupts from all 4, 8 or 16 UARTs on the board and manages them to produce interrupts on a single line on the PC bus. This is not as simple as just ORing them all together to produce an interrupt signal. The IBM PC bus interrupt lines are edge-triggered, which means that a low to high transition needs to take place in order to create a new interrupt. This causes a problem for the hardware designer. In an ORed logic scheme with two UARTS, the following sequence of events could hang the board up:</p>
<ol>
<li/>UART 2 generates an interrupt, bringing PC IRQ high
<li/>The interrupt service routine (ISR) is invoked
<li/>The ISR checks UART 1, which is idle
<li/>The ISR checks UART 2, sees that it is active
<li/>UART 1 receives a character, generates an interrupt
<li/>The ISR services UART 2
<li/>UART 2 drops its interrupt line, PC IRQ remains high because of UART 1
<li/>The ISR exits
</ol>
<p>At this point, the IRQ line on the PC is still high, but a new interrupt will not be generated. This is because it did not go low after UART 2 was serviced, so an edge was not generated.</p>
<p>The Multiport boards have to intelligently manage the interrupt output going on to the PC bus. The exact method varies from board to board, but the final outcome is the same: an edge needs to be generated for each interrupt that needs to be serviced by the CPU. This implies circuitry somewhat more sophisticated than just a giant OR gate, but doesn't require revolutionary new designs. This allows the board designers to keep the prices at a reasonable level.</p>
<p>All the boards that will be discussed in this article manage the interrupts in this manner. Each of the boards also incorporates an additional feature that helps the programmer: a status register. When the board generates an interrupt, there is a special register on the board that can be read by the interrupt service routine. This register indicates which port(s) are presently in need of servicing. Without this register, the interrupt service routine would have to poll each UART on the board for its current interrupt activity. The status register makes that job a little easier.</p>
<p>The multiport boards discussed in this article differ somewhat from RS-232 interface boards that readers may have seen on various other system. First of all, the 8250 family of UARTs are not considered to be high performance parts. Boards designed for systems such as DEC's VAX line of minicomputers can select the optimum UART for the job, since all system access goes through a device driver. PC board designers don't have this luxury, and must stick to the compatible family of parts, for better or worse.</p>
<p>An even more important distinction between PC multiport boards and those found on other systems is the requirement of processor intervention on every single character event. Higher powered boards relieve the system CPU of "character juggling" through many different mechanisms.</p>
<p>Generally these boards will have a dedicated processor that takes care of processing individual interrupts, buffering data, and transferring it to the main CPU memory via DMA or shared memory. Even if a slave processor is not available, many UARTs have FIFOs that can drastically reduce the number of interrupts required when processing data.</p>
<p>These intelligent boards suffer from only two problems: they cost an arm and a leg, and they are for the most part incompatible with the existing PC code base. So when an application requires support for 4 or more RS-232 lines, it makes sense to look at the lower cost, dumb-but-compatible multi-port boards.</p>
<h4>When to Select an 8250 Family Multiport Board</h4>
<p>When you have an application that needs to be able to service 4 or more RS-232 ports, you have several choices, including intelligent boards, networked systems, and multiport boards. The decision making process on which board to choose is fairly simple. As long as cost is an important factor, the multiport board board is your first choice. The end user price of under $100/port is well below the price of an intelligent board.</p>
<p>The primary drawback to the multiport board is one of throughput. As was discussed earlier, the CPU in your PC will have to individually transfer each byte from the UART to PC memory, or vice versa. By adding up the number of cycles needed to process each character, you can quickly get an idea of the maximum throughput on a PC. Even with carefully crafted assembly code, a 10 Mhz 80286 machine will only be able to keep up with perhaps 4-6 ports running continuously at 9600 baud. At that rate the CPU will be receiving a new interrupt about once every 250 microseconds, which is barely enough time to save and restore all the registers.</p>
<p>Fortunately, RS-232 throughput for most applications tends to be "bursty". An AT machine will have no trouble managing 8 or even 16 ports in an application where data is being sent only periodically. Think of a typical Point-of-Sale terminal application. Most terminals attached to the PC will be idle most of the time. As long as the processor can send the 2000 or so characters needed to redraw a screen in a second or so, it will have plenty of breathing room to catch up while the clerk runs the customer's Visa card through the imprinting machine.</p>
<p>One additional advantage to consider when selecting a type of board is the availability of library software. Most of the multiport boards discussed in this article have support available from several C and Pascal library vendors. The intelligent boards for the most part are limited to device drivers supplied by the vendor. These device drivers generally implement a basic feature set, but are short on bells and whistles. The competitive environment in the third-party library arena has created a buyer's market, with extensive feature lists available for library purchasers. Sources for these libraries are discussed at the end of this article.</p>
<h4>The Software</h4>
<p>Given that you now have an application that needs one of these multiport boards, and you have purchased one and installed it in your computer, what do you do next? Just having the board itself is not enough, you now need an interface to control and communicate with the RS-232 ports resident on it. The code to do this breaks down into three major sections:</p>
<ul>
<li/>The control interface, used to open and close ports, and set and change parameters, such as the baud rate.
<li/>The Input/Output interface, used by the programmer to read and write single characters, or blocks of characters.
<li/>The device interface code, used to handle the physical level interface with the multiport board.
</ul>
<p>The conventional way to talk to a piece of hardware in the computer world is through a device driver, which is either part of or closely linked to the operating system of the computer. In the MS-DOS world, if you are talking to a device driver you can generally use the standard I/O routines that are supplied with your programming language.</p>
<p>Unfortunately, for various reasons, device drivers on MS-DOS machines will frequently not perform as well as we would like. This leads programmers to use shortcuts that talk directly to the hardware. Serial communications software is no exception to this.</p>
<p>The device driver built into the IBM PC BIOS for the RS-232 ports is of very little value. Since it is a polled mode interface, about the only thing it can reasonably be used for is an output-only interface, such as to a printer. In addition, multiport boards are unknown to the BIOS, so any device driver to support these boards must be added in as a separate program. Most manufacturers of multiport boards do in fact supply device drivers for their boards. Some are true device drivers which are installed via modification of the MS-DOS CONFIG.SYS configuration files. Others are TSR programs which can be installed and removed at any time on a running system.</p>
<p>Using the vendor supplied software can be a good or bad idea. The true MS-DOS device drivers allow you to open ports in C with standard fopen() commands, and read and write with putc() and getc(). Other vendors require you to learn new commands and link in their library routines. At the most inconvenient end of the scale, some vendors emulate the INT 14 BIOS service calls for their COM ports, requiring you to learn the arcane syntax of your particular compiler's version of the int86() function.</p>
<p>All of these are reasonable solutions, but they generally suffer from one or more disadvantages. First of all, the device drivers tend to be somewhat inflexible. MS-DOS does not support loading or unloading device drivers, so they usually have to be left in at all times, imposing an unwelcome burden on applications that don't need them.</p>
<p>Communicating with devices via system interrupts is usually slower than direct function calls. And most importantly, there are a lot of times when you want to have the source to your device interface code, and you don't usually get that from a board vendor.</p>
<p>Fortunately, it is not that difficult to implement your own code to talk to a multiport board. Most C compilers being sold today have the capability to implement a complete interface without having to resort to any assembly code, and still achieve satisfactory performance. As an example, I have supplied some sample code with this article that does just that, and all in only a little more than a hundred lines of C code.</p>
<h4>The Sample Device Interface</h4>
<p>The code for interfacing to the multiport board is contained in the file called COM.C. For the most part, this code glosses over the details of programming the 8250 UART. Various computer magazines have published many good articles over the past few years detailing how this part works, and the reader unfamiliar with the part can refer to these. In addition, I would recommend ordering the data sheets from National Semiconductor. </p>
<p>The code in COM.C is compatible with Microsoft C, Quick C, and Turbo C. The major difference to be handled between the two dialects of C is their implementation of the I/O port input and output routines, and the get and set interrupt routines. These differences are managed through the use of macros conditionally defined in the COM.H header file.</p>
<p>In order to understand how to use this code, you need to look at the procedural interface to the code. The data structures remain mostly hidden from view. In order to understand how the code works, you need to look at those data structures, and examine how they interface with the code.<br />
Data Structures</p>
<p>There are two major types of data structures in this program, and once you understand how they work, the rest of the program's operation quickly makes sense. The two data structures are the BOARD structure and the PORT structure. The PORT structure is very similar to the structure you might use in a conventional single port program. The definition of type PORT in COM.H is shown below:</p>
<pre>
typedef struct {
    unsigned int   address;     /* Address of the 8250                */
    char           buffer[256]; /* The receive buffer.                */
    unsigned char  head;        /* Offset for insertion into the buff.*/
    unsigned char  tail;        /* Offset for removal from the buffer.*/
    unsigned char  match;       /* The status register match value    */
} PORT ;
</pre>
<p>The structure elements are as follows:</p>
<table border="0">
<tr>
<td valign="top" width="15%">address:</td>
<td>This is the base address of the 8250 UART. It is needed to read and write characters, as well as to control the UART, set operational parameters, etc.</td>
</tr>
<tr>
<td valign="top">buffer[256]:</td>
<td>This is a simple 256 byte receive circular buffer. The arbitrary size of 256 was chosen to simplify the put and get routines.</td>
</tr>
<tr>
<td valign="top">head:</td>
<td>This is the buffer offset used by the interrupt service routine to add characters to the circular buffer.</td>
</tr>
<tr>
<td valign="top">tail:</td>
<td>This is the buffer offset used to remove characters from the receive buffer.</td>
</tr>
<tr>
<td valign="top">match:</td>
<td>This byte is used to show what bits need to be set in the board status register to indicate that this port has an interrupt needing servicing.</td>
</tr>
</table>
<p>The only structure element that wouldn't normally be used in a single port operation is the "match" element. Depending on the board type, the match can either indicate which bit is set for the given port in the board status register, or what value in the status register will indicate the port is active. (Digiboard is the only board using the latter algorithm).</p>
<p>The BOARD data structure is a little different. A BOARD structure is what is attached to a particular interrupt line, and it in turn has to keep track of the PORT structures that are owned by a particular board.</p>
<p>The structure elements for BOARD are described here:</p>
<table border="0">
<tr>
<td valign="top" width="20%">status_address:</td>
<td>This is the address of the status register for the particular board.</td>
</tr>
<tr>
<td valign="top">irq_mask:</td>
<td>This is the mask that has to be applied to the system 8259 interrupt controller in order to enable and disable interrupts. Note that this structure element is redundant, and could be calculated given the interrupt number. Storing it in the structure just means it doesn't have to be recalculated every time interrupts are enabled and disabled.</td>
</tr>
<tr>
<td valign="top">int_number:</td>
<td>This is the CPU interrupt number that the board is attached to. On the PC, this will typically be 11 or 12 for IRQ3 and IRQ4 respectively.</td>
</tr>
<tr>
<td valign="top">old_vector:</td>
<td>When the board is opened, the old interrupt vector is stored here. When the board is closed, that interrupt vector is replaced.</td>
</tr>
<tr>
<td valign="top">ports[4]:</td>
<td>This array holds pointers to the four ports that can be attached to this board. Note that for other types of boards, this array could be 8 or 16 elements long.</td>
<tr>
<tr>
<td valign="top">port_count:</td>
<td>This value indicates how many elements of the ports[] array are presently installed.</td>
</tr>
</table>
<h4>The Code</h4>
<p>There are only eight routines in the COM.C file, and they implement a complete interface to a multiport board. In this case, the code was written to support a Stargate Technologies Plus-8 board, but it only requires changing a line or two in the interrupt service routine to support other boards. The routines are described below:</p>
<p><strong>board_open( address, number ) :</strong></p>
<p>This routine is called to perform the logical connection between a multiport board and an interrupt line on the PC. The <em>address</em> parameter is the address of the status register on the board. The <em>number</em> is the interrupt number to be used on the PC. For the first 8 interrupts on the ISA bus, the interrupt number is 8+IRQn, so IRQ3 and IRQ4 will have interrupt number 11 and 12. This routine initializes the BOARD data structure and returns a pointer to that structure. It saves the old interrupt vector, sets up a new interrupt vector, and enables interrupts on the specified line.</p>
<p><strong>board_close( board ) :</strong></p>
<p>This routine is called to shut down a given board, specified by the "board" parameter. board_close() takes care of disabling interrupts on the correct interrupt line, then restoring the interrupt vector that was in place before the board was opened. It also takes care of closing any of the ports attached to it that have not been closed with an explicit call to port_close().</p>
<p><strong>port_open( board, address, match ) :</strong></p>
<p>This routine is called to open a single port up, and attach it to the board it belongs with. The <em>board</em> parameter is a pointer to the BOARD structure, which should have already been opened. The <em>address</em> parameter is the base address of the UART, and the match parameter is used in the interrupt service routine to check for the status register bit indicating that this particular UART has an interrupt pending.</p>
<p><strong>port_set( port, speed, parity, data, stopbits ) :</strong></p>
<p>This routine is called after the port has been opened. It sets up the baud rate, parity, number of data bits, and number of stop bits for the port specified in the <em>port</em> parameter. After the parameters are set up for the port, receiver interrupts on that port are enabled.</p>
<p><strong>port_close( port ) :</strong></p>
<p>port_close is called to shut down the UART. All it does is disable interrupts on the selected UART, then free up the space that had been allocated for the port structure. The way the routines are presently written, board_close() will call this routine for each open port, so it doesn't need to be called by the application.</p>
<p><strong>port_putc( port, c ) :</strong></p>
<p>This routine is analagous to the fputc() routine in the C standard i/o run time library. It is passed a character and a pointer to a port data structure. It sits in a loop and waits for the UART to have space available in its transmit holding register. When the UART is ready to send another character, this routine stuffs it into the holding register and returns.</p>
<p><strong>port_getc( port ) :</strong></p>
<p>port_getc() is analagous to the fgetc() routine in the standard i/o library. It doesn't have to talk directly to the UART, since incoming characters are being stored in the circular buffer. It checks to see if there are any characters in the buffer, and extracts and returns one if there are. If no characters are available, an error code is returned.</p>
<p><strong>interrupt_service_routine() :</strong></p>
<p>The final routine found in COM.C is interrupt_service_routine(), which is not called by any routines outside of the COM.C file. It is the routine that is branched to when an interrupt is generated by the board. Its job is to service any and all interrupts pending on the multiport board. The way the routine determines which ports need servicing is by reading the status register. Once the status register has been read in, the ISR can loop through the list of open ports, looking for ports that have bits set in the status register.</p>
<p>The device dependent portion of the code is found in the interrupt service routine. The way the ISR decides whether to service a port on the Stargate board is by executing the following lines:</p>
<pre>
for ( i = 0 ; i &lt; board.port_count ; i++ )
{
    if ( board.ports[i]-&gt;match &amp; status_reg) {
                     .
                     .
                     .
</pre>
<p>The <em>match</em> value in each port structure has been set up in my sample program for the Stargate status register, where each port has a single bit in the status register. Other boards may expect the bit to be cleared for the given port. The Digiboard products don't use a bit pattern in the status register, they actually put a single port number in the register. These differing cases would only require a minor change to <em>if</em> line of code in the ISR.</p>
<h4>The Test Program</h4>
<p>In order to test this interface code, I wrote a short program called MULTTERM. This program creates four windows on the screen which each have an independent terminal session taking place concurrently. The way I wrote the program allows the user to switch the keyboard between the four windows by pressing Function keys 1 through 4. Even though keyboard input can only be directed to one port at a time, all four ports are actively receiving input characters at all times, and displaying them on the screen as they arrive.</p>
<p>The program consists of four modules that can be compiled separately and linked together. There are also three header files. The files are listed below:</p>
<table border="0">
<tr>
<td valign="top" width="20%"><a href="/attachments/1991/comports/multterm.c">MULTTERM.C</a>:</td>
<td>This is the file that contains main(), and drives the test program. All of the other files contain the support and driver routines.</td>
</tr>
<tr>
<td valign="top"><a href="/attachments/1991/comports/com.c">COM.C</a>:</td>
<td>This is the file that has all of the routines that interface to the multiport board.</td>
</tr>
<tr>
<td valign="top"><a href="/attachments/1991/comports/keys.c">KEYS.C</a>:</td>
<td>This contains the routine to get keys from the keyboard.</td>
</tr>
<tr>
<td valign="top"><a href="/attachments/1991/comports/video.c">VIDEO.C</a>:</td>
<td>This contains a "quick and dirty" windowed interface to the display. It is hard coded for CGA/EGA/VGA displays.</td>
</tr>
<tr>
<td valign="top"><a href="/attachments/1991/comports/com.h">COM.H</a>:</td>
<td>The function prototypes and structure definitions needed to use the communications functions.</td>
</tr>
<tr>
<td valign="top"><a href="/attachments/1991/comports/video.h">VIDEO.H</a>:</td>
<td>The function prototypes and constants needed to use the display interface functions.</td>
</tr>
<tr>
<td valign="top"><a href="/attachments/1991/comports/keys.h">KEYS.H</a>:</td>
<td>Function prototypes and key definitions for the keyboard interface.</td>
</tr>
</table>
<p>The operation of MULTTERM.C is relatively simple. The program consists of only three sections. In the first section, four non-overlapping windows are opened up. In the second section of code, the board and the four ports are opened up. My test board was set up with a status register at address 0x580, and the UARTs spaced 8 addresses apart starting at 0x180. The Stargate Plus board uses a single bit in the status register to indicate that a port needs servicing, so the port parameters look like this:</p>
<table border="1">
<tr>
<td width=30%"><center>Port</center></td>
<td width="30%"><center>Status Register Bit</center></td>
<td width="30%"><center>UART Base Address</center></td>
<tr>
<tr>
<td><center>0</center></td>
<td><center>1</center></td>
<td><center>180H</center></td>
</tr>
<tr>
<td><center>1</center></td>
<td><center>2</center></td>
<td><center>188H</center></td>
</tr>
<tr>
<td><center>2</center></td>
<td><center>4</center></td>
<td><center>190H</center></td>
</tr>
<tr>
<td><center>3</center></td>
<td><center>8</center></td>
<td><center>198H</center></td>
</tr>
<tr>
<td><center>4</center></td>
<td><center>16</center></td>
<td><center>1A0H</center></td>
</tr>
<tr>
<td><center>5</center></td>
<td><center>32</center></td>
<td><center>1A8H</center></td>
</tr>
<tr>
<td><center>6</center></td>
<td><center>64</center></td>
<td><center>1B0H</center></td>
</tr>
<tr>
<td><center>7</center></td>
<td><center>128</center></td>
<td><center>1B8H</center></td>
</tr>
</table>
<p>Finally, after the ports are opened, the main terminal emulation loop is entered. This main loop has two sections. In the first section, the input buffers for all four ports are emptied out, with all the characters being written out to the appropriate display window. Once this is done, the second section is entered. This is where the keyboard is read. An Escape key causes an immediate exit, a Function key causes a switch to a particular window, and any other key is output to the appropriate communications port.</p>
<p>To test the operation of this system, I ran it on a standard 10Mhz XT, and connected it to Xenix system on four different ports. A sample screen capture is shown here:</p>
<pre>
----------------------------------------------------------------------------
|                                    ||23%                                 |
|17%                                 ||23% w -t                            |
|17% tty                             ||  3:24pm  up 1 day, 21:08,  5 users,|
|/dev/ttyi1a                         || load average: 0.00, 0.00, 0.00     |
|18% cat > /dev/ttyi1b               ||24%                                 |
|Message...                          ||24% tty                             |
|Message line two...                 ||/dev/ttyi1b                         |
|19%                                 ||25% Message...                      |
|                                    ||Message line two...                 |
|                                    ||                                    |
----------------------------------------------------------------------------
----------------------------------------------------------------------------
|Message  1:                         ||                                    |
|From nelson Sun Mar 18 15:22:48 1990||4% mail nelson                      |
|To: nelson                          ||Subject: Stargate                   |
|Subject: Stargate                   ||This message is being sent          |
|Date: Sun Mar 18 15:22:48 1990      ||through a Stargate board.           |
|                                    ||(end of message)                    |
|This message is being sent          ||5%                                  |
|through a Stargate board.           ||                                    |
|                                    ||                                    |
|d                                   ||                                    |
----------------------------------------------------------------------------
</pre>
<p><center>A MULTTERM Screen</center></p>
<p>The sample program was built using the following QuickC 2.0 command line:</p>
<pre>
QCL /W3 MULTTERM.C VIDEO.C COM.C KEYS.C
</pre>
<p>If you are using Borland's Turbo C 2.0, use this line:</p>
<pre>
TCC -w MULTTERM.C VIDEO.C COM.C KEYS.C
</pre>
<p>The only differences between the two versions of the program are the names of the routines to get and set interrupt vectors, and the routines to input and output bytes to I/O ports. These differences are handled by #define statements in COM.H. Note that this program can be ported easily to any MS- DOS compiler that supports interrupt service routines written in C.</p>
<p>The test program operated fine on the XT, although I didn't subject it to heavy data traffic. It was able to receive data simultaneously on all four windows without losing any characters. However, if I want to keep up with continuous data on multiple ports I would either need to upgrade to a faster machine or optimize both my Com port and display I/O routines.</p>
<h4>Software Improvements</h4>
<p>If you wanted to develop the routines shown here into a production quality library, there are quite a few areas that would benefit from attention. Most of the refinements can be done one at a time, allowing for a steady evolutionary improvement in your library. Some of the most beneficial improvements would be:</p>
<ul>
<li/>Allowing for adjustable buffer sizes. 256 bytes may prove to be far to small for some applications.
<li/>Interrupt driven transmission, as well as reception. This requires modification of the ISR to check for the type of interrupt.
<li/>Hardware and software handshaking, including XON/XOFF, RTS/CTS, and DTR/DSR.
<li/>Support of more than one board operating at a time.
<li/>Hand coding of the interrupt service routine in assembly language for maximum optimization.
<li/>Break detection on the incoming line.
<li/>Adding lines to check the status of the incoming modem status lines.
<li/>Detection of parity errors, overrun errors, etc.
<li/>Protection from uncontrolled exit of your program without disabling interrupts.
</ul>
<h4>Hardware Sources</h4>
<p>There are quite a few different companies making multiport boards for the PC bus family of machines. A few of the names and phone numbers of companies whose hardware I have used are shown below. The biggest demand for these types of boards has in the past come from users of multitasking operating systems, so the manufacturers have tended to advertise in Unix oriented magazines. If you want to do more research, this would be a good place to look. This is not intended to be a comprehensive list, and any time you spend doing research in area will probably be worthwhile.</p>
<p>Commtech, Inc.<br />
Wichita, KS<br />
316-651-0077</p>
<p>Contec U.S.A<br />
San Jose, CA<br />
800-888-8884</p>
<p>Digiboard, Inc.<br />
St. Louis Park, MN<br />
612-922-8055</p>
<p>Quadram<br />
Norcross, GA<br />
404-923-6666</p>
<p>Quatech, Inc.<br />
Akron, Ohio<br />
800-553-1170</p>
<p>Stargate Technologies, Inc.<br />
Solon, Ohio<br />
216-349-1860<br />
Software Sources</p>
<p>It is relatively easy to go into business selling C libraries. All you need is a few months of time to develop a product, and a little seed money for advertising. This fact, combined with the high demand for quality libraries, has resulted in there being at least a dozen companies selling C libraries for serial communications. With this many entrants in the market, a "features war" has developed, resulting in a good buyers market. For less than $300, you can buy libraries that have an enormous amount of functionality. Most of these library vendors have ads in the pages of this magazine, so the research job is relatively simple. Armed with the list of functions you need, you should be able to estimate the amount of effort required to write your own code. Given this, you are ready to make a build or buy decision.</p>
<p>In addition to the commercial market, there are a few public domain and shareware serial communications libraries available. However, I am not aware of any that offer support for multiport boards. Of course, it could be practical to modify one of these libraries to suit your particular needs.</p>
<h4>Conclusion</h4>
<p>In order to use more than two RS-232 ports on a PC, you need to purchase a multiport board. While this does mean you have to either build or buy some non-standard device interface software, this can be done without too much new code. So if you have an application that demands communication with multiple source of information in the real world, this can provide an economical means of accomplishing your goal.</p>
]]></content:encoded>
			<wfw:commentRss>http://marknelson.us/1991/04/01/what-to-do-when-youre-past-com2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Servicing COM Port Interrupts</title>
		<link>http://marknelson.us/1990/05/01/servicing-com-port-interrupts/</link>
		<comments>http://marknelson.us/1990/05/01/servicing-com-port-interrupts/#comments</comments>
		<pubDate>Tue, 01 May 1990 14:38:52 +0000</pubDate>
		<dc:creator>Mark Nelson</dc:creator>
				<category><![CDATA[Magazine Articles]]></category>
		<category><![CDATA[Serial Communications]]></category>

		<guid isPermaLink="false">http://marknelson.us/?p=357</guid>
		<description><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/1990/05/01/servicing-com-port-interrupts/' addthis:title='Servicing COM Port Interrupts' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div>This article first appeared in the May, 1990 issue of Tech Specialist The COM ports on an IBM compatible PC provide MS-DOS users with an extremely versatile avenue for communications with other devices. Yet experienced PC programmers find that the operating system and their compiler libraries offer them with very little in the way of [...]]]></description>
			<content:encoded><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/1990/05/01/servicing-com-port-interrupts/' addthis:title='Servicing COM Port Interrupts' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div><table align="left" cellspacing="5" border="0">
<a name="part1"></a></p>
<tr>
<td><center><image src="/attachments/1990/comports/covera.gif"></center></td>
<tr>
<td><b>This article first appeared in the<br/> May, 1990 issue of <br/>Tech Specialist</b></td>
</tr>
</table>
<p>The COM ports on an IBM compatible PC provide MS-DOS users with an extremely versatile avenue for communications with other devices. Yet experienced PC programmers find that the operating system and their compiler libraries offer them with very little in the way of useful tools for using these COM ports. Fortunately, C compiler technology has advanced to the point where it is now practical to implement an interrupt driven communications system entirely in C. This article discusses some of the techniques for accomplishing this.<br />
<span id="more-357"></span></p>
<h4>A Brief History of COM</h4>
<p>The original design for the IBM PC included provisions in the hardware and the BIOS for the support of RS-232 communications ports. The BIOS supports up to four COM ports, but both MS-DOS and the hardware design reduced the number of ports that could practically be used to two. These ports are referred to by their MS-DOS device names, COM1 and COM2. The designers chose the 8250 series of UARTs from National Semiconductor, and implemented a single port communications card that supported the following items:</p>
<ul>
<li/>Interrupt or polled input and output.
<li/>Modem control output lines RTS, DTR.
<li/>Modem control input lines CTS, DSR, RI and CD.
<li/>Baud rates up to 115200 bps.
</ul>
<p>Unfortunately the BIOS implementation for the COM ports restricted these capabilities somewhat. The BIOS functions for the COM port do not support interrupt driven I/O, and only allow eight discrete baud rate settings which range up to 9600 bps. MS-DOS uses the BIOS for all of its COM port functions, so the BIOS provides the limits on what functions programmers have available using the operating system.</p>
<p>Using the COM port for output-only applications, such as for spooling to a printer, works fairly well using this built-in support. The application operates in a somewhat inefficient mode, since it is effectively idled for the duration of its output, but it is able to get maximum throughput out of the port, even at higher baud rates.</p>
<p>But when MS-DOS programmers try to use the COM ports for applications that require both input and output, they are quickly stymied. Even at rates as low as 1200 baud, polled mode software has to sample the input port at rates that create incredible scheduling problems within programs. At the highest BIOS supported rate of 9600 baud, a program would have to sample the UART once every millisecond without fail. This is essentially impossible.</p>
<p>This leaves the programmer with only one option for programs that need to make full use of the COM port: using interrupt driven communications. This allows the program to go off and do some work while characters are being read into a buffer and/or being pulled out of a buffer and passed through the UART. The idea behind this sounds attractive, but most programmers feel that implementing this type of code is extremely difficult.</p>
<p>At one time this was certainly true, but advances in C compiler implementation have reduced the level of effort needed to solve this problem. Unlike four or five years ago, it is now relatively easy to implement an interrupt service routine that manages the UART without ever having to leave the comfort of your C compiler. This is a marked change from the days where this type of code had to be developed from assembly language. This article will demonstrate how to write this type of code using both Microsoft C &#038; Borland's Turbo C.</p>
<h4>The UART</h4>
<p>Writing device interface code requires that you understand the hardware. In this case, the hardware to interface with is the 8250/16450/16550 family. The original PC was equipped with 8250 UARTs. The AT began using the 16450 UARTs, and some of the newest machines are now being equipped with 16550s. The two newer members of this UART family are completely downward compatible with the 8250, so code written for it will run without modification on newer machines.</p>
<p>The 8250 has 11 internal registers that the programmer can access. On the IBM compatible PC, these registers are laid out on the I/O bus, rather than being mapped into memory. This means that the C programmer needs to access the registers using the inp() and outp() library routines. The register definitions are accessed through eight consecutive port locations. The function of each of the 11 registers is discussed in detail in this section.the following offsets and conventional mnemonics</p>
<h4>RBR: Receiver Buffer Register (Offset 0)</h4>
<p>This is the holding register that receives a character after the UART has finished reading it in from the RS-232 line. Since the UART is double buffered, the receive can be working on reading in the next character while at the same time waiting for the CPU to read the character out of the RBR. This give the programmer approximately one character time to respond the character being read in. This is a read-only register.</p>
<h4>THR: Transmit Holding Register (Offset 0)</h4>
<p>This is a write-only register that accepts a character to be sent out of the UART. As soon as the UART transmitter is available, the character is moved out of the holding register and into the transmitter and starts going out on the RS-232 line.</p>
<h4>IER: Interrupt Enable Register (Offset 1)</h4>
<p>This register has four bits that individually enable each of the four different types of interrupts that the 8250 family can generate. The bit masks and the interrupt types are:</p>
<table border="0">
<tr>
<td valign="top" width="10%">1</td>
<td>The Received Data Available interrupt. This interrupt is generated when a character is transferred out of the receiver and into the receiver buffer, where the CPU can then access it.</td>
</tr>
<tr>
<td  valign="top">2</td>
<td>The Transmit Holding Register Empty interrupt. When this interrupt is enabled, an interrupt is generated whenever the Transmit Holding Register is empty. This generally occurs when a new character is moved out of the THR and into the transmitter.</td>
</tr>
<tr>
<td  valign="top">4</td>
<td>The Receiver Line Status interrupt. Setting this bit will cause an interrupt to be generated whenever an abnormal line condition occurs. These conditions are read out of the Line Status Register, and are: Overrun Error, Parity Error, Framing Error, and Break Interrupt. While the sample program in this article doesn't use this interrupt, it is frequently used when these conditions need close monitoring.</td>
</tr>
<tr>
<td  valign="top">8</td>
<td>The Modem Status interrupt. Setting this bit will cause an interrupt to be generated whenever one of the four incoming RS-232 Modem Status Lines changes. They are CD, RI, CTS, and DSR. This program doesn't use this interrupt, but it is useful when using CTS or DSR for handshaking.</td>
</tr>
</table>
<h4>IIR: Interrupt Identification Register (Offset 2)</h4>
<p>When an interrupt occurs, the Interrupt Service Routine (ISR) reads this register to determine what caused the interrupt. The register contains one of five values, four for the four different interrupt types, with one more for "no interrupt pending". The values read out of the IIR are:</p>
<table border="0">
<tr>
<td valign="top" width="10%">1</td>
<td>No interrupt pending.</td>
</tr>
<tr>
<td valign="top">0</td>
<td>A modem status change interrupt. This means the state of CTS, DSR, RI or CD has changed.</td>
</tr>
<tr>
<td valign="top">2</td>
<td>Transmit Holding Register Empty. This means that a new character can be written to the Transmit Holding Register.</td>
</tr>
<td valign="top">4</td>
<td>Received Data Available. A new character has been read in by the UART, and can be read from the Receiver Buffer Register.</td>
</tr>
<tr>
<td valign="top">6</td>
<td>A Line Status Interrupt has taken place. This means an overrun error, Parity Error, Framing Error, or Break Signal has occurred.</td>
</tr>
</table>
<h4>LCR: The Line Control Register (Offset 3)</h4>
<p>This register has control over how the UART sends and receives characters. All eight bits of this register are used, with the following definitions and bit masks:</p>
<table border="0">
<tr>
<td valign="top" width="10%">0-3</td>
<td>These four bits set the word length for input and output. 0=5 bits, 1=6 bits, 2=7 bits, and 3=8 bits.</td>
</tr>
<tr>
<td valign="top">4</td>
<td>If set, two stop bits are generated for each output byte, otherwise one stop bit is generated.</td>
</tr>
<tr>
<td valign="top">8</td>
<td>If set, Parity bits are both checked and generated. If clear, no parity bits are added to output bytes, and none are checked.</td>
</tr>
<tr>
<td valign="top">16</td>
<td>If parity is on, setting this bit selects even parity, clearing selects odd parity.</td>
</tr>
<tr>
<td valign="top">32</td>
<td>If this bit is set, parity is stuck at either a 1 or a 0, depending on the setting of the previous bit, mask 16. If it is clear (as it is normally), parity of output is selected by bits 3 and 4.</td>
</tr>
<tr>
<td valign="top">64</td>
<td>In order to output a break, this bit can be set. As long as it is held, the UART will be kept in a spacing condition, which causes the remote end to receive a break.</td>
</tr>
<tr>
<td valign="top">128</td>
<td>This is the Divisor Latch Access bit. Setting it disables the normal states of registers 0 and 1 and converts them to Divisor Latch registers. This bit needs to be set in order to set or change the baud rate.</td>
</tr>
</table>
<h4>MCR: The Modem Control Register (Offset 4)</h4>
<p>The Modem Control Register has five bits that can be set or cleared by a program. They are listed here, along with the bit masks used to set or clear the bits:</p>
<table border="0">
<tr>
<td valign="top" width="10%">1</td>
<td>Data Terminal Ready is controlled by this bit. The sample program shown here asserts DTR when the port is opened, and leaves it there as long as the port is open.</td>
</tr>
<tr>
<td valign="top">2</td>
<td>Request To Send is controlled by this bit. The terminal emulation program included with this article leaves RTS on as long as the port is opened, but this line is frequently used as a handshaking line when performing RTS/CTS handshaking. In that case it will be dropped low when the input buffer passes a certain high water mark.</td>
</tr>
<tr>
<td valign="top">4</td>
<td>OUT1 is controlled by this bit. OUT1 has no function on the IBM PC COM cards.</td>
</tr>
<tr>
<td valign="top">8</td>
<td>OUT2 is controlled by this bit. On most IBM compatible COM cards, OUT2 is used to gate the interrupt line to the PC bus. If OUT2 is not asserted, no interrupts can occur. So in this program, OUT2 is left on.</td>
</tr>
<tr>
<td valign="top">16</td>
<td>This is the loopback bit. On 8250 UARTs this can be used to loopback all data written to the UART, allowing for on-line diagnostics without a loopback connector. Because of a slight change in the design of the part, loopback tests usually won't work properly on the 16450. During loopback the 16450 will drop the OUT2 line, effectively turning interrupts off.</td>
</tr>
</table>
<h4>LSR: The Line Status Register (Offset 5)</h4>
<p>The Line Status Register has seven bits that contain various status indicators relating to the actual transmission of data. The error bits and the break indicator can be read directly from this register. They will also generate an interrupt when they are set, so they can be read from inside an interrupt service routine to eliminate the need to poll this register. The bits and masks that can be set in this register are:</p>
<table border="0">
<tr>
<td valign="top" width="10%">1</td>
<td>Data Ready. This bit indicates that there is a byte ready to be read out of the Receiver Buffer Register. In interrupt mode, this bit is of no interest. When in polled mode, this bit is monitored until set, when a character can be read.</td>
</tr>
<tr>
<td valign="top">2</td>
<td>Overrun Error. This bit indicates that a character came in before the last one was read out of the Receiver Buffer. This means the receiver is not being serviced rapidly enough, which can occur for many different reasons. If this bit is set it means that at least one input character was lost.</td>
</tr>
<tr>
<td valign="top">4</td>
<td>Parity Error. This bit indicates that a character came in with a different parity set than what was selected in the Line Control Register. If no parity is being used, this bit will never be set.</td>
</tr>
<tr>
<td valign="top">8</td>
<td>Framing Error. When the receiver is clocking a new character in, it expects to see at least one stop bit after the end of the character. The stop bit provides spacing between characters. If the stop bit is not present, a Framing Error is generated. Framing errors frequently mean either a noisy line or mismatched baud rates.</td>
</tr>
<tr>
<td valign="top">16</td>
<td>Break Interrupt. This line is set when the receiver detects a break. A break is indicated if the RS-232 input line is held low for longer than an entire character time, including the time allocated for a start bit and stop bit.</tr>
</td>
<tr>
<td valign="top">32</td>
<td>Transmitter Holding Register Empty. When operating in polled mode, the CPU waits for this bit to be set before writing another character to the THR. When transmitting in interrupt mode, this bit is not generally useful.</td>
</tr>
<tr>
<td valign="top">64</td>
<td>Transmitter Empty. When this bit is set, it means that not only is the THR empty, but the transmitter is empty as well. This means both buffers in the double buffered UART are empty. One of the times it could be useful to watch this bit is when a process needs to wait until it can be reliably sure that all characters have actually been transmitted before performing some action.</td>
</tr>
</table>
<h4>MSR: The Modem Status Register (Offset 6)</h4>
<p>For each of the incoming four modem status lines, there are two bits in this register. One of the bits is used to detect the state of the line. This line can be polled at any time to determine what the state of a particular line is. The other bit is used when a Modem Status interrupt occurs. This bit, called the delta bit, indicates which lines have changed state, causing the interrupt. If modem status interrupts are being used, the delta bits can be examined to determine which line caused the interrupt. The bits in the MSR are defined as follows:</p>
<table border="0">
<tr>
<td width="10%">1</td>
<td>Delta Clear To Send</td>
</tr>
<tr>
<td>2</td>
<td>Delta Data Set Ready</td>
</tr>
<tr>
<td>4</td>
<td>Trailing Edge Ring Indicator</td>
</tr>
<tr>
<td>8</td>
<td>Delta Carrier Detect</td>
</tr>
<tr>
<td>16</td>
<td>Clear To Send</td>
</tr>
<tr>
<td>32</td>
<td>Data Set Ready</td>
</tr>
<tr>
<td>64</td>
<td>Ring Indicator</td>
</tr>
<tr>
<td>128</td>
<td>Carrier Detect</td>
</tr>
</table>
<h4>SCR: The Scratch Register (Offset 7)</h4>
<p>There is a spare register in the 8250 that can be used as a storage area. It is generally not used for anything in the IBM PC compatible development environment.</p>
<h4>DLL &#038; DLM: Divisor Latch LSB and MSB (Offset 0 and 1, DLAB=1)</h4>
<p>The Baud Rate at which the 8250 transmits and receives data is established by dividing a master clock by a 16 bit divider. The master clock on the IBM PC COM card is operating at an effective rate of 115,200 Hz. Thus, a divider of 12 yields a baud rate of 9600. Since the UART has an 8 bit wide data path, the divider has to be loaded in two registers. On the 8250, the least significant byte of the divisor is loaded into register 0, and the most significant byte is loaded into register 1.</p>
<p>The problem with these two registers is that the designers of the 8250 found that they came up a couple short on registers in their address map. They could either expand the address space to 10 registers, or play some tricks with they space they had. They opted for the tricks. In order to access the baud rate divisor registers, there is a bit in the Line Control Register that must be set. This bit, the Divisor Latch Access Bit, temporarily changes the function of registers 0 and 1 while it is set. So to load the baud rate, the code normally sets DLAB to 1, writes to register 0 and 1, then restores DLAB to its normal setting of 0.</p>
<h4>Writing The Interface Code</h4>
<p>Despite the fact that there are so many registers, control lines, bits and bytes to keep track of on this UART, it is still relatively easy to develop a fully featured communications interface to it. The sample program developed here only uses 6 routines, none of which take up more than a screenful of code.</p>
<p>The code presented here uses interrupts for both input and output. While this adds some complexity to the software, it should also increase the overall performance of a program by relieving the processor of the dead time incurred during polled output. It also makes the code much easier to modify for support of hardware handshaking, which requires the use of Modem Status Interrupts. An ISR supporting multiple interrupt types will also make it easy to add interrupt based detection of line errors to this code.</p>
<p>The interface to a device of any kind has five basic types of functions that are needed in order to operate the device:</p>
<ul>
<li/>An open function, to establish a link with the device.
<li/>A control function, to manipulate device parameters.
<li/>An input function, to receive data from the device.
<li/>An output function, to send data to the device.
<li/>A close function, to break the link with the device.
</ul>
<p>In a comprehensive library, there will be multiple functions in many of the five categories, but the basic five provide a platform on which to start building.</p>
<h4>The Port Structure</h4>
<p>Before looking at the interface functions to the COM port, it is a good idea to understand what is stored in the PORT structure. The PORT structure is analogous to the FILE structure used by the C standard I/O library. When a COM port is opened, the PORT structure is returned, and all future access to the COM port is done through the structure. The definition of the PORT structure, found in Listing 2, COM.H is:</p>
<pre>
typedef struct {
    void (interrupt far * old_vector)();
    int  uart_base;
    int  irq_mask;
    int  interrupt_number;
    BUFFER  in;
    BUFFER  out;
} PORT ;
</pre>
<p>The buffer structure is defined previously in the COM.H file as:</p>
<pre>
typedef struct {
    char buffer[256];
    unsigned char write_index;
    unsigned char read_index;
} BUFFER;
</pre>
<p>Once a COM port is opened, the information in the PORT structure can be used to perform any of the functions needed to manipulate it. The structure members have the following definitions:</p>
<table border="0">
<tr>
<td valign="top" width="20%">old_vector:</td
<td>This is the interrupt vector that was in place for the port when it was first opened. This is stored in the structure so that it can be restored when the port is closed.</td>
</tr>
<tr>
<td valign="top">uart_base:</td>
<td>This is the base address of the UART on the I/O bus, i.e. the first register.</td>
</tr>
<tr>
<td valign="top">irq_mask:</td>
<td>This is the bit mask that is applied to the 8259 interrupt controller in order to enable or disable interrupts from the device. Turning off interrupts at the 8259 doesn't actually disable interrupts from the UART, it just ensures that the system will never respond to them.</td>
</tr>
<tr>
<td valign="top">interrupt_number:</td>
<td>This is the software interrupt number for the UART. The first eight interrupts on the PC have software interrupts 8-15. IRQ3 and IRQ4 correspond to interrupt 11 and 12, and this is where that COM ports will typically go.</td>
</tr>
<tr>
<td valign="top">in:</td>
<td>This is the input buffer structure. It is where characters that are received by the UART go. The application program will pull characters out of this buffer using the port_getc() command.</td>
</tr>
<tr>
<td valign="top">out:</td>
<td>This is the output buffer structure. It is where characters go that are going to be transmitted by the UART. The UART takes characters out of this buffer in the Interrupt Service Routine.</td>
</tr>
</table>
<p>The structure of the input and output buffers in this program is fairly simple. They are implemented as 256 byte circular buffers with each one having a read index and a write index. For both the input and the output, only one process is allowed to modify the write_index, and only one process is allowed to modify the read index. This simplifies the code, since interrupts do not have to be disabled during the routines that insert and delete characters from the buffer. For example, on the input buffer, the port_getc() routine is allowed to increment the read_index when extracting a character, and the interrupt service routine is allowed to increment the write_index when inserting a character. An additional simplifying factor with these buffers is their size, 256 bytes. This means that the indices for the buffers can be one byte, and the increment procedure will inherently roll the pointers over when they reach their maximum. In point of fact, most applications will find 256 bytes to be too small for both the input and output buffers, and will have to increase the size. The code for managing the indices in this case will also get a little larger.</p>
<h4>The Open Function</h4>
<p>The open function needs to establish a logical link with a particular device. In the case of a COM port on a PC, the minimum amount of information to establish the connection would be the COM port number, 1 or 2. In order to provide a little more versatility, I had my routine require as parameters the UART base address and the CPU interrupt number. The function prototype is:</p>
<pre>
PORT *port_open( int address,
                 int int_number )
</pre>
<p>This requires an extra parameter beyond what would be needed for just using COM1 or COM2, but it does allow the routine the flexibility to deal with non-standard COM port implementations. There are quite a few variations of COM3 and COM4 that are circulating about, and this routine should be able to handle all of them. Note that like its counterpart in the C standard I/O library, fopen(), port_open() returns a pointer to a structure. The PORT structure contains all of the information needed for future operations on the port.</p>
<p>The actual code for port_open is shown in Listing 3. The space for the PORT structure is allocated with a call to malloc. The input and output buffer pointers are both initialized. The UART address and interrupt parameters are initialized. The existing UART interrupt vector is stored, and a new one is established. The new interrupt vector points to the interrupt vector in COM.C. Finally, the 8259 Interrupt Controller on the PC bus is told to start accepting interrupts from the UART. Note that the UART won't start generating interrupts yet, because it has not had its interrupts enabled yet. It would be unwise to enable interrupts before setting the rest of the operating parameters.</p>
<p>There are two lines in the port_open routine that store the DOS CTRL-BREAK vector off and establish our own private interrupt handler for CTRL-BREAK processing. This is done so that the user can't break out of the program without giving the code a chance to turn off interrupts and restore the old interrupt vectors. Note that in a communications system that was supporting multiple ports simultaneously, this processing would only be done when the first port was opened, so there would need to be a flag set once the CTRL-BREAK vector was subverted to insure that it only happened once.</p>
<h4>The Control Procedure(s)</h4>
<p>After a program has opened a COM port, it needs to set the baud rate, number of bits, parity, etc. for the port. Depending on the number of features available in the package, there may be many control procedures. Some may act directly on the UART, others will operate on the data structure associated with the UART. My implementation of a control procedure is a single function, called port_set(), which allows the caller to set the baud rate, parity, number of data bits, and number of stop bits for a COM port. The parameters are the same and in the same order as the DOS MODE command. The prototype for the port_set() procedure is:</p>
<pre>
void port_set(PORT *port,
              long speed,
              char parity,
              int data,
              int stopbits);
</pre>
<p>The code for this routine, shown in Listing 3, accomplishes this in a straightforward manner, by updating all the relevant registers in the UART. Before any changes can occur, all interrupts in the UART are disabled. At that point, the registers are all updated. Note that it is imperative to have interrupts disabled while the baud rate is being changed. If an interrupt occurred while DLAB was set to 1, the interrupt service routine would think it was accessing the Receive or Transmit data buffers, when in fact it was modifying the divisor registers.</p>
<p>This routine also turns on DTR, RTS, and OUT2. OUT2 has to be enabled on the IBM PC COM card in order for interrupts to occur. A complete package would allow the user some control over DTR and RTS, but adding those functions to this package should be straightforward. Finally, after all is ready, this routine turns Receive interrupts back on. At that point, any incoming characters will be received by the Interrupt Service Routine and inserted into the input buffer.</p>
<h4>The Input Function</h4>
<p>Input and output functions take on quite a few different forms, and it is unlikely that any single function would do. However, I have implemented just a single function here, port_getc(), which attempts to get a single character from the input buffer for the port. Understanding how this routine works would allow you to easily build other functions, such as port_get_buffer(), port_getc_with_timeout(), port_get_string(), etc.</p>
<p>The input function here, port_getc(), receives just a single parameter, which is a pointer to the port data structure. It doesn't talk to the UART at all. Rather, it just looks to see if there are any characters in the input buffer, and extracts one if there is. It returns an error immediately if there are no characters available. An alternative way to implement this function would be to wait either for a fixed amount of time or indefinitely if no characters are available.</p>
<h4>The Output Function</h4>
<p>The output function for the sample communications package is called port_putc(). Its prototype is:</p>
<pre>
int port_putc( unsigned char c, PORT *port )
</pre>
<p>This routine has to first check to see if the output buffer is already full. If it is, an error is returned. (Note that it would be a simple matter to modify the routine so it just waited for there to be room in the buffer). In the event that there is room in the buffer, the single character is inserted. Note that the character must be placed in the buffer before the index is incremented. When writing code like this, you have to consider the ramifications of an interrupt occurring at any point in any operation during the routine.</p>
<p>This routine differs from the port_getc() routine in one respect: it has to actually communicate directly with the UART. The reason for directly modifying the UART is that Transmit interrupts are continually being enabled and disabled on the UART. When no characters are present in the buffer, it is necessary to turn off the Transmit interrupt, otherwise it would be generated continuously. This means that after a new character is inserted into the buffer, the port_putc() routine needs to see if Transmit interrupts are already enabled. If they aren't, this routine enables them. This starts the chain of events that leads to a Transmit Interrupt occurring, and the character that has been placed in the buffer being transmitted.</p>
<p>It is probably more common for programmers to implement this routine as a polled mode function. The code both in this routine and in the Interrupt Service Routine is shortened somewhat when this is done, at the expense of a certain amount of efficiency. A polled mode version of port_putc() would look like this:</p>
<pre>
int port_putc( unsigned char c, PORT *port )
{
  while ( (inportb( port-&gt;uart_base + LSR ) &#038; LSR_TEMT ) == 0 )
    ;
  outportb( port-&gt;uart_base, c );
}
</pre>
<h4>The Close Function</h4>
<p>A program that has enabled interrupts on the COM port has to be careful to restore the computer's configuration back to "normal" before exiting the program. Failure to do so could leave interrupts enabled on the port. After the program exits, the interrupt service routine will no longer be in memory, so if an interrupt occurs, disaster will follow.</p>
<p>The close function here is called port_close(). All it takes as an argument is a pointer to the port structure:</p>
<pre>
void port_close( PORT *port );
</pre>
<p>The first thing port_close() does is disable all interrupts on the UART. That by itself is enough to restore things to a safe state, but it does a couple of more things in the interest of cooperation with other programs. First, it disables the selected interrupt at the 8259 Interrupt Controller, and then restores the interrupt vector that was in place before the program was selected. Finally, it restores the system CTRL-BREAK handler. Note that if a program is written to use multiple ports, you would only want to restore the system break handler when the last port is closed, or the program exits.</p>
<p>When the port is closed, this code drops DTR and RTS. This should have the effect of letting any device attached to the PC know that the port is no longer active. For example, if a modem was attached to the COM port, and it had a call in progress, dropping DTR should cause it to hang up.</p>
<p>One way this port_close() routine could be drastically improved would be by saving the settings of the COM port when it was opened so it could be completely restored when closed. Right now, the port is left in an arbitrary state on exit. If a previous program had the port set up with a certain baud rate and parity settings, these routines would obliterate them. It is not too hard to add the code to the port_open() routine to read in all the register settings of the UART before it is opened. Then, those settings can be restored upon exit. This should include the settings of the 8259 interrupt controller as well. This kind of attention to detail would be mandatory if, for example, you were writing a COM program that would be a TSR.</p>
<h4>The Interrupt Service Routine</h4>
<p>The heart of the communications port interface code is the Interrupt Service Routine. This is where all the bytes get moved in and out of the UART. This is also the one part of the interface code that the application program never sees.</p>
<p>If you were going to write an interrupt service routine for a C program 3 or 4 years ago, you would have had to get out the Assembly Language reference books, install a copy of MASM, and start doing some low level bit twiddling. But today, both Microsoft and Borland have built into their compilers the function type modifier "interrupt". If you declare a C procedure to be type "interrupt", the compiler takes care of some important details for you. First of all, it saves all the registers, which a normal C routine doesn't do. Secondly, it loads the DS segment register with a pointer to DGROUP, the default data segment. And in the exit code for the routine, it restores all the registers, and then returns with an "iret" instruction instead of the normal "ret".</p>
<p>There are still quite a few precautions you have to take when writing an interrupt service routine in C. You are precluded from using most of the run time library, as the routines are generally not written to be re-entrant. You probably don't want to call any DOS or BIOS functions, for the same reasons. And you need to be very careful about calling other C routines. For example, if the other C routines have stack overflow checking turned on, they will probably abort when called from inside an interrupt service routine.</p>
<p>With all that in mind, it is still possible to write a fully functional ISR in C. The ISR written for this routine is shown in Listing 3. The 8250 ISR is relatively simple. It sits in a loop, reading in the Interrupt Identification Register over and over, servicing each interrupt type as it appears. When it finally reads the IIR and sees that no more interrupts are pending, it exits the ISR.</p>
<p>The reason the 8250 ISR has to continually read the IIR until all interrupts have been dealt with is due to the way the PC hardware is configured. The 8259 interrupt controller on the PC is configured to be edge sensitive. It will only detect an interrupt on a device when the interrupt line makes an OFF to ON transition. If we were to exit our 8250 Interrupt Service Routine without servicing all of the interrupt types that were pending, the 8250 would keep its interrupt line ON, thinking that this would get the processor's attention later on. However, the 8259 interrupt controller would assume that since the UART hadn't brought the line down yet, it was still being serviced from the previous interrupt. So it is necessary to clear out all pending interrupt conditions on the device before exiting.</p>
<p>The Interrupt Service Routine has a switch() statement that examines the IID, and goes to one of five cases upon reading the result. The first four are for the conventional interrupt sources. In the case of Modem Status Register and Line Status Register interrupts, the ISR just reads the appropriate register to clear out the interrupt. Since this program isn't using those interrupts, they should never be executed anyway.</p>
<p>The IIR_RECEIVE case in the ISR is called when there is a new character in the receiver buffer. The first the ISR does is read the character out of the RBR, which clears the interrupt source. Then, if there is room in the input buffer, the character it received is queued up in the buffer. A useful addition here would be to set an error flag when a character is received but can't be inserted into the buffer.</p>
<p>The IIR_TRANSMIT case is branched to when the Transmit Holding Register is empty. This occurs in one of two cases. When transmit interrupts are first enabled by port_putc(), an interrupt occurs immediately, since the THR is empty at that time. The other case is when the Transmitter Register empties out, and the old character in the THR is moved into the transmitter. At this point, the UART is ready for another character, and an interrupt is generated.</p>
<p>The IIR_TRANSMIT code first checks to see if a character is ready in the output buffer. If one is ready, it is pulled out of the buffer and written out to the THR. If no characters are in the buffer, it is time to shut down transmitter interrupts, as they are no longer needed. The next time port_putc() is called, they will be started back up.</p>
<p>The final case in the IID switch() statement is for when there are no further interrupts pending. In this case, the EOI indicator is written out to the 8259 interrupt controller so it knows that the interrupt has been serviced.</p>
<p>One of the alternative ways to handle COM port I/O that was discussed in this article was the idea of only allowing receiver interrupts, and having the transmit done with polled I/O. If this is done, it will greatly simplify the interrupt service routine, since it can assume that every interrupt is a receiver interrupt. In that case, the ISR will look like this:</p>
<pre>
static void interrupt far interrupt_service_routine()
{
  if ((com-&gt;in.write_index+1 ) != com->in.read_index)
    com-&gt;in.buffer[ com->in.write_index++ ] =
      (unsigned char) inportb( com-&gt;uart_base + RBR );
  outportb( INT_CONTROLLER, EOI );
}
</pre>
<h4>Putting It All Together</h4>
<p>In order to test and demonstrate this code, I created a very short terminal program, which is found in TERM.C, in Listing 1. After opening the port and setting up the transmission parameters, the program just sits in a loop polling the keyboard and COM port for input. Keyboard characters are sent out through the COM port. Characters read in from the COM port are displayed on the screen using putc(). Hitting the Escape key shuts down the port and exits.</p>
<p>While this is not a very useful program, it does provide a good test bed for the program. However, I was able to use it to verify the most important fact, which was that the interrupt service routine was able to keep up with a steady stream of incoming data at 9600 baud on a standard XT without missing any incoming characters. Using putc() for output, the program wasn't able to output the characters to the screen fast enough to keep up, but I was able to get around that by switching over to direct video access, and less frequent polling of the keyboard.</p>
<p>In order to build this program using QuickC, enter:</p>
<pre>
qcl /W3 /Ox term.c com.c
</pre>
<p>Using Turbo C, enter:</p>
<pre>
tcc -w term.c com.c
</pre>
<h4>Enhancements</h4>
<p>The communications interface presented here is more than adequate for many applications. And in the places where it isn't adequate, it provides a framework for developing enhancements. Some enhancements that immediately come to mind are:</p>
<p><em>Optimization of the three most heavily used portions of the code</em>: port_putc(), port_getc(), and the interrupt service routine. All three are candidates for rewriting in assembly code for speed. Port_putc() and port_getc() are candidates to be rewritten as macros so they can be called in line, saving some overhead.</p>
<p><em>Adding hardware and/or software flow control</em>: XON/XOFF handshaking is frequently needed when performing terminal emulation, and RTS/CTS or DSR/DTR handshaking is useful when talking to a variety of devices such as printers and modems.</p>
<p><em>Modifying the code so it can simultaneously support multiple ports</em>: The PORT structure has already encapsulated all of the data for a COM port, so this could be accomplished relatively easily. The main thing that needs to be done is to provide special handling for things that only need to be done once, like interception of the CTRL-BREAK function. The atexit() function would be a useful way to implement this.</p>
<p><em>Adding detection for incoming break characters, and other line status errors.</em></p>
<p><em>Adding support for the 16 byte receive and transmit FIFOs on the 16550 UARTS</em>: This allows data to be moved in and out with far fewer interrupts occurring, resulting in much more efficient code.</p>
<p>This code can provide a useful added capability to your programming toolkit, and takes care of a noticeable gap in the MS-DOS library of device drivers. Best of all, the code is actually portable across several of the leading MS-DOS C compilers, and doesn't require you to understand assembly language. So if you have an application that needs to take advantage of RS-232 communications, you can now take the plunge with full confidence that the project can be accomplished.</p>
<h4>Listings</h4>
<table border=0">
<tr>
<td width="20%">Listing 1:</td>
<td width=70%"><a href="/attachments/1990/comports/term.c">term.c</a></td>
</tr>
<tr>
<td width="20%">Listing 2:</td>
<td width=70%"><a href="/attachments/1990/comports/com.h">com.h</a></td>
</tr>
<tr>
<td width="20%">Listing 3:</td>
<td width=70%"><a href="/attachments/1990/comports/com.c">com.c</a></td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://marknelson.us/1990/05/01/servicing-com-port-interrupts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

