Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Porting Communications Software to Windows CE


Sep99: Porting Communications Software to Windows CE

Oliver is Langner's project manager for the Windows CE version of LUCA. He can be contacted at [email protected].


If you're to believe Microsoft, porting a Win32 application to Windows CE is a piece of cake, because almost all of the well-known Win32 APIs are there. When porting LUCA, a universal software-development framework for data communications, to Windows CE, however, we discovered that fact differs from fiction (for more about LUCA, see "LUCA: Reusable Communication Code," by Bennett Griffin, DDJ, October 1997). We learned the hard way that porting software from Windows 95/NT to CE can be an even more demanding task than porting to a nonMicrosoft target operating system.

LUCA supports all popular transport protocols (including TCP/IP, async, sync, and ISDN) for all contemporary development environments (including C++, Delphi, Visual Basic, and Java). You can use LUCA, for instance, to transmit e-mail from applications as well as to access programmable logic controllers (PLCs) in a factory automation environment or to perform Zmodem file transfers. LUCA's internal architecture features a modular structure consisting of protocol and driver modules that can be stacked together at run time in a Streams-like manner. LUCA was designed with portability in mind. For this reason, we chose C as our implementation language. Nevertheless, LUCA can be used with any modern programming language and includes C++ classes, VCLs, and ActiveX controls on top of its kernel API functions. (An evaluation version of LUCA is available for download at http:// www.langner.com/.) With all conceivable operating-system dependencies implemented in isolated source modules, we felt porting the code would be a straightforward and manageable task. We didn't consider that even trivial standard library functions such as sprintf() can cause portability trouble.

The Unicode Problem

Unicode is a standard for character representation to facilitate software internationalization. The big difference between ASCII and Unicode is that the latter uses 2 bytes per character, making a 65,536-character alphabet possible. Windows 3.x did not support Unicode. Windows 95 offers limited support for Unicode. With Windows NT, you have a real choice between ASCII and Unicode. Windows CE uses Unicode as its only character representation, therefore ASCII is not an option. Unfortunately, Unicode does not make a lot of sense for use in data communications. For example, transport protocols such as SMTP or Zmodem strictly require ASCII control and address information, sometimes even limited to 7 bits per character. The proposed UTF-8 standard addresses this problem. When it comes to message content, another argument against Unicode is effective transmission speed. If you are transmitting all your text messages using 2 bytes per character, you are effectively cutting your bandwidth in half (unless you are using Kanji, where you need 2 bytes per character anyway) -- which is something most users wouldn't want to do just for internationalization. All in all, it seems that the field of data communication is too closely tied to 8-bit characters to replace ASCII with something else over night.

To support ASCII, we implemented several string processing functions from stdio.h and stdio.c (available electronically; see "Resource Center," page 5). Unfortunately, Unicode conversion was not the only compatibility problem in respect to standard library functions. Neither should you expect to find io.h or time.h anywhere for the CE environment. Here again, we had to implement our own open(), write(), and close() functions, as Listing One illustrates.

The Overlapped I/O Trap

When it came to porting LUCA's async serial interface module to CE, we didn't expect serious problems because our Windows 95/NT implementation uses Win32 function calls such as ReadFile() and WriteFile(), which are readily available under CE. However, system functions for I/O are not compatible between Windows 95/NT and CE. Consequently, you must use a Windows 95/NT functionality called "overlapped I/O" to perform event-driven communications. Overlapped I/O is activated by a data structure called OVERLAPPED (defined in winbase.h), which is also used to install an event handler for events such as receive data available.

Unfortunately, Microsoft didn't define OVERLAPPED for Windows CE. Since we needed event handlers for any type of serious data-communications application, there was no alternative but to use a completely different implementation for async serial transmission -- one that featured a multithreaded core process that calls the application's event handlers. We needed one thread to monitor modem status lines, another to watch for "transmitter empty" situations, and yet another thread to process "receive data available" situations. Although, in theory, this multithreaded implementation should work unchanged under Windows 95/NT, in real life it does not, due to an incompatibility of the CreateFile(), ReadFile(), and WriteFile() system functions. Without the OVERLAPPED flag, your code will block under Windows 95/NT, making simultaneous reads and writes impossible. Incidentally, Windows CE expects you to refer to the first async serial port using the filename COM1: (in Unicode). Windows 95/NT refers to the same port using \\.\COM1 (in ASCII). In short, there is no way to write a portable serial I/O interface for Windows 95/NT and CE. The only solution is to implement two different software modules for the same task.

TAPI Trouble

Any modern library for async serial communications is expected to handle dial-up modem connections using Microsoft's Telephone API (TAPI). A benefit of using TAPI is that applications can take advantage of all the stored modem configurations within Windows, which frees the application from keeping its own AT configuration strings in some kind of "modem database." That's great, but on the other hand, TAPI is so complex and weird that you need third-party tools to actually use it.

TAPI is supposedly available in Windows CE. The good news is that TAPI function calls are mostly compatible with Win32 (with the exception that all strings are expected in Unicode). The bad news is that Microsoft seems to have decided that dial-in connections are not required for CE applications (or maybe the dial-in stuff just didn't make the deadline). In any event, you can establish dial-out connections with CE's TAPI version, but not dial-in connections. Perhaps a future version of the operating system will fix this. Until then, LUCA users can get around this shortcoming using LUCA's built-in ATMODEM driver that supports both dial-out and dial-in connections for data, fax, and voice transmission.

The Debugging Drama

Compiling and linking a CE application is always done on a Windows NT host computer. After your CE implementation is ready for testing, there are basically two options for debugging: You can run and debug the application within NT's CE emulator, or you can choose remote debugging after the application is downloaded to the CE target system. Host debugging using the CE emulator is convenient and timesaving. Actually, you don't notice many differences to debugging a regular NT application. The problem with remote debugging is that it's painfully slow, even if you use a 115-Kbps async link between the target and the host system. And remember, your application has to be downloaded to the target every compile and test cycle.

Unfortunately, there are situations when the search for bugs has to be done blindly because no debug option is available. We encountered this with LUCA's async serial interface. The CE emulator's async driver within NT doesn't work well, so all testing had to be done on the target system. If your CE machine has only one async serial port (like most handheld PCs), you can use this port either for remote debugging or for the application's purposes -- but not for both.

Conclusion

Eventually we ported most of LUCA's major protocol modules to Windows CE, resulting in a portable software development framework for async serial transmission, including fax, voice, short message system (SMS), and factory automation protocols. To demonstrate the portability as well as the ease of LUCA, Listing Two is C++ code for transmitting a fax (using a conventional dial-up fax modem).

The remarkable thing about this code (besides being surprisingly short) is that it works unmodified with Windows 95/98/NT/CE. If you followed the discussion of incompatibilities and debugging hurdles, you will have an idea of how much development time was required to reach this goal. As far as data communications is concerned, you don't have to spend the same effort and time that we did if you just use LUCA.

DDJ

Listing One

vfcntl.h
#ifndef _VFCNTLH_INCLUDED
#define _VFCNTLH_INCLUDED

#define _O_RDONLY       0x0000  /* open for reading only */
#define _O_WRONLY       0x0001  /* open for writing only */
#define _O_RDWR         0x0002  /* open for reading and writing */
#define _O_APPEND       0x0008  /* writes done at eof */

#define _O_CREAT        0x0100  /* create and open file */
#define _O_TRUNC        0x0200  /* open and truncate */
#define _O_EXCL         0x0400  /* open only if file doesn't already exist */

#define _O_TEXT         0x4000  /* file mode is text (translated) */
#define _O_BINARY       0x8000  /* file mode is binary (untranslated) */

#define O_RDONLY        _O_RDONLY
#define O_WRONLY        _O_WRONLY
#define O_RDWR          _O_RDWR
#define O_APPEND        _O_APPEND
#define O_CREAT         _O_CREAT
#define O_TRUNC         _O_TRUNC
#define O_EXCL          _O_EXCL
#define O_TEXT          _O_TEXT
#define O_BINARY        _O_BINARY
#define O_RAW           _O_BINARY
#define O_TEMPORARY     _O_TEMPORARY
#define O_NOINHERIT     _O_NOINHERIT
#define O_SEQUENTIAL    _O_SEQUENTIAL
#define O_RANDOM        _O_RANDOM

#endif /* _VFCNTL_INCLUDED */

vio.h
#ifndef _VIOH_INCLUDED
#define _VIOH_INCLUDED

extern int open( const char *filename, int oflag);
extern int write( int handle, const void *buffer, unsigned int count );
extern int close( int handle );

#endif /* _VIOH_INCLUDED */

vio.c
#ifdef _WIN32_WCE
#include <windows.h>
#include <tchar.h>
#include <luca/mach.h>
#include <luca/vfcntl.h>
#include <luca/vstdio.h>

int open( const char *filename, int oflag)
{
    V_USES_CONVERSION
    DWORD access = 0, creation = 0; 
    if (oflag & O_RDONLY) access = GENERIC_READ;
    else if (oflag & O_WRONLY) access = GENERIC_WRITE;
    else if (oflag & O_RDWR) access = (GENERIC_WRITE | GENERIC_READ);
   if ((oflag & O_APPEND) && (oflag & O_CREAT)) creation = OPEN_ALWAYS;
    else if (oflag & O_APPEND) creation = OPEN_EXISTING;
    else if (oflag & O_CREAT) creation = CREATE_NEW;
    
    return (int) CreateFile(VTEXT(filename), access, 0, NULL,
                                 creation, FILE_ATTRIBUTE_NORMAL, NULL);
}
int write( int handle, const void *buffer, unsigned int count )
{
    DWORD counter;
    WriteFile((void*) handle, buffer, count, &counter, NULL);
    return counter;
}
int close( int handle )
{
    return CloseHandle((void*) handle);
}
#endif /* _WIN32_WCE */

Back to Article

Listing Two

void CFaxDlg::OnSend() 
{
    USES_CONVERSION;                // see MSDN TN059 
    Vport fax;                      // LUCA port object
    CString faxno, text, linkid;
    const char *linkid_ascii, *text_ascii;

    EditFaxNo.GetWindowText(faxno);     // get faxno from edit control 
    EditText.GetWindowText(text);       // get message text from edit control

    linkid = _T("sff/fax/atmodem:") + faxno + 
                                 _T("/async/com:1,speed=19200,flow=xonxoff");
                // LUCA link identifer: use structured fax format converter 
                // (SFF) over class 2 fax transmission (FAX) via Hayes 
                // compatible modem (ATMODEM) connected to COM1 (COM) 
    linkid_ascii = T2CA(linkid);            // convert UNICODE to ASCII
    text_ascii = T2CA(text);

    fax.Vopen(linkid_ascii);        // open LUCA port, start dialing 
    fax.Vctl(V_WTIMEOUT, 60000);    // set write timeout
    fax.Vwrite(text_ascii, strlen(text_ascii)); // send message
    fax.Vclose();                   // close connection, LUCA will wait until 
                                    // your fax has been sent
}

Back to Article


Copyright © 1999, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.