Where can I find serial port sample code?

Q) Does anyone have any C sample code showing how to use the serial port under OS/2 using DosOpen() and DosDevIoCtl()?

A) As a matter of fact, yes. :-)

-=-= extracted from a silly & specialized program =-=-=-=-==-=-=

/* dtp.c -- D-dial Terminal Program: the first hack */

//-- an annoying detail

#define INCL_BASE
#define INCL_DOSDEVIOCTL  /* docs lie, this is NOT included by BASE */
#include <os2.h>

//-- initialization (in main() as written)

    HFILE portFd;
    ULONG action;

    if (DosOpen("COM1", &portFd, &action, 0, FILE_NORMAL, FILE_OPEN,
      OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE, 0) != 0) {
        fprintf(stderr, "Open of COM1 failed\n");
        goto error0;
    }

    {	DCBINFO di;
        ULONG dummy;

        dummy = sizeof(di);
        if (DosDevIOCtl(portFd, IOCTL_ASYNC, ASYNC_GETDCBINFO, 0, 0, 0,
                        &di, sizeof(di), &dummy) != 0)
            fprintf(stderr, "DosDevIOCtl failed\n");
        else {
            fprintf(stderr, "Timeouts: read = %u, write = %u\n",
                    di.usWriteTimeout, di.usReadTimeout);
            fprintf(stderr, "Flag bytes: %02x, %02x, %02x\n",
                    di.fbCtlHndShake, di.fbFlowReplace, di.fbTimeout);
        }
        di.fbTimeout = (di.fbTimeout & ~(3 << 1)) | (2 << 1);
                                          /* rcv = wait-for-something */
        di.usReadTimeout = 250;
        dummy = sizeof(di);
        if (DosDevIOCtl(portFd, IOCTL_ASYNC, ASYNC_SETDCBINFO,
                        &di, sizeof(di), &dummy, 0, 0, 0) != 0)
            fprintf(stderr, "DosDevIOCtl failed to set parameters!\a\n");
    }

    if (initSerialOutput(portFd) != 0)
        goto error1;

//-- the "running" variable is sort of a relic, I think

    running = 1;
    if (_beginthread(serialInputThread, 0, 8192, (void *)portFd) < 0) {
        fprintf(stderr, "can't start serial input thread\n");
        goto error2;
    }

    if (_beginthread(serialOutputThread, 0, 8192, (void *)portFd) < 0) {
        fprintf(stderr, "can't start serial output thread\n");
        goto error2;
    }

//-- wrapup code

    shutdownSerialOutput();
    DosClose(portFd);

//-- the rest of this lives outside of main()...

//-- input side: gory details omitted

//-- the port has been setup in "wait for something" mode, so we can request
//-- more than one character at a time without blocking until the buffer is
//-- full.  At least, I *think* that's working now: this is used with 300 baud
//-- systems, so it's hard to tell <g>.  At least it isn't blocking until the
//-- buffer is filled...

/*  serialInputThread -- reads port, writes to text window
*
*   arg is the port's handle for reading
*/
void serialInputThread(void *arg)
{
    HFILE inFd = (long)arg;
    FILE *logFile;
    UCHAR buf[10];

    ParserState ps = {0};

    logFile = fopen("dtp.log", "ab");

    for ( ; ; )
    {
        ULONG n;
        if (DosRead(inFd, buf, 10, &n) == 0)
        {
            ULONG i;
            for (i = 0; i <n; ++i)
            {
                if (logFile != 0)
                    putc(buf[i], logFile);
                if (runParser(&ps, buf[i]) != 0)
                    postChar(buf[i]);
            }
        }
    }
}

/* output side: I rather like this arrangement using queues
   except that I'd prefer an anonymous queue.
   For this, having the queue named in the
   filesystem's name space is at best a minor annoyance. */

/* * * *    SerialOutput subsystem
*/

#define MAX_CHUNK_SIZE 50

typedef struct
{
    USHORT nUsed;
    UCHAR buf[MAX_CHUNK_SIZE];
} SO_CHUNK;

#define NUM_SO_CHUNKS 6


HQUEUE soQueue, freeQueue;


int initSerialOutput (HFILE outFd)
{
    (void) outFd;     /* reserved for more general version */

    if (DosCreateQueue
       (&soQueue, QUE_FIFO, "\\queues\\dtp\\soQueue") != 0)
    {
        fprintf(stderr, "Failed to create serial output queue\n");
        goto error0;
    }
    if (DosCreateQueue
       (&freeQueue, QUE_FIFO, "\\queues\\dtp\\freeQueue") != 0)
    {
        fprintf(stderr, "Failed to create serial free queue\n");
        goto error1;
    }
    {   SO_CHUNK *p = malloc(sizeof(SO_CHUNK) * NUM_SO_CHUNKS);
        int i;
        if (p == 0)
        {
            fprintf(stderr,
            "Failed to allocate memory for serial chunks\n");
            goto error1;
        }
        for (i = NUM_SO_CHUNKS; 0 < i; --i)
            if (DosWriteQueue(freeQueue, 0, sizeof(SO_CHUNK), p++, 0)
            != 0)
            {
                fprintf(stderr, "Failed to initialize free queue\n");
                goto error1;
            }
    }

    return 0;

error1:
    DosCloseQueue(soQueue);
error0:
    return -1;
}


void shutdownSerialOutput(void)
{
    DosCloseQueue(freeQueue);
    DosCloseQueue(soQueue);
}


void writeSerial(UCHAR const *buf, USHORT n)
{

    while (0 < n)
    {
        REQUESTDATA rd;
        ULONG dataLength;
        PVOID data;
        BYTE priority;

        if (DosReadQueue(freeQueue, &rd, &dataLength, &data,
                         0, DCWW_WAIT, &priority, 0) == 0)
        {
            SO_CHUNK *sc = data;
            USHORT m = MAX_CHUNK_SIZE;
            if (n < m)
                m = n;
            memcpy(sc->buf, buf, m);
            sc->nUsed = m;
            DosWriteQueue(soQueue, 0, sizeof(SO_CHUNK), sc, 0);
            buf += m;
            n -= m;
        }
    }
}


void writeSerialString(UCHAR const *buf)
{
    writeSerial(buf, strlen(buf));
}


void serialOutputThread(void *arg)
{
    HFILE outFd = (long)arg;
    REQUESTDATA rd;
    ULONG dataLength;
    PVOID data;
    BYTE priority;

    for ( ; ; )
    {
        if (DosReadQueue(soQueue, &rd, &dataLength, &data,
                         0, DCWW_WAIT, &priority, 0) == 0)
        {
            if (rd.ulData == 0) {     /* simple data block */
                ULONG dummy;
                SO_CHUNK *sc = data;
                DosWrite(outFd, sc->buf, sc->nUsed, &dummy);
                DosWriteQueue(freeQueue, 0, sizeof(SO_CHUNK), sc, 0);
            }
            else
                ;  /* anything else is a test, ignore it */
        }
    }
}

The intention was that control messages could be posted to the queue using null data packets (passing the actual message in the REQUESTDATA.ulData field); these would allow for controlling the port's baud rate and other settings. This seems to work under 2.0, and even appears to be intended to work (Deitel & Kogan's description), but I haven't done anything with it yet, as you can see. Haven't needed the facility yet...

Credit: Martin Maney


[Back: What do all those keywords mean when making a DLL?]
[Next: How do I disable ?]