Member Avatar for CaptainProg

Hi

I'm trying to use the outportb() function to send a signal to a RS-232 serial port. I understand that in order to use the function I need to #include <dos.h> and <conio.h>.

I am using Dev-C++ as my compiler and am having no luck when compiling the code. I am told that the function is undefined. My code is as follows (I am trying to send '2' on port '0x3FC':

#include <conio.h>
#include <dos.h>
#include <stdio.h>

int main()
{
outportb(0x3FC,2);
return 0;
}

I am very new to C++ though so may be missing something obvious. The only error message I receive is '`outportb' undeclared (first use this function)'.

Any help would be appreciated; for now I am simply trying to send the signal down the port. The device I have attached to the port is an LED which should light up when the signal is successfully sent.

Recommended Answers

All 6 Replies

Those sorts of low-level direct I/O calls (in the spirit of inp()/outp()) no longer work under Windows (as of NT and later) without a special device driver.

For an alternative look into the Win32 API functions like CreateFile.

See this PDF as the author seems to go through those functions step by step.

commented: Yup. +16

You will also need to explicitly instruct Windows to associate your port with a COM device. You can find instructions here.

Finally, you would be aware that only "COM1" through "COM9" are specifiable like that. If you associate a port with a larger device number, you'll have to specify it with a string like "\\\\.\\COM24" , as described in this article. The same string will work for the normal port numbers also, as in "\\\\.\\COM2" .

Hope this helps.

commented: nice useful info. +17
Member Avatar for CaptainProg

Thanks for the help so far. I have used the PDF example provided by Jonsca to create an empty Win32 application which so far only seems to execute the useful code when the program exits. I'm not sure as to why this is, but the device is successfully triggered and flashes when I close the program. At the moment, the only solution I can think of is to write a separate program that opens and closes my (slightly dodgy) program every time I want the LED to light up. This is obviously not the ideal solution. My code is shown below. Please note that I couldn't get the 'Setting Parameters' section of the help PDF to compile so it is omitted. I suppose it is quite possible that it is there that the problem lies.

THIS CODE IS ESSENTIALLY JUST THE CODE PROVIDED IN THE HELP DOCUMENT. I suspect problems are to be found around lines 114-127 and 144-147.

#include <windows.h>
//These three might not be neccesary?
#include <stdlib.h>
#include <string.h>
#include <tchar.h>

//<Initialise Windows module> 
        /*  Declare Windows procedure  */
        LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
        
        /*  Make the class name into a global variable  */
        char szClassName[ ] = "WindowsApp";

        int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

    {
                        HWND hwnd;               /* This is the handle for our window */
                        MSG messages;            /* Here messages to the application are saved */
                        WNDCLASSEX wincl;        /* Data structure for the windowclass */

           /* The Window structure */
           wincl.hInstance = hThisInstance;
           wincl.lpszClassName = szClassName;
           wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
           wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
           wincl.cbSize = sizeof (WNDCLASSEX);

           /* Use default icon and mouse-pointer */
           wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
           wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
           wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
           wincl.lpszMenuName = NULL;                 /* No menu */
           wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
           wincl.cbWndExtra = 0;                      /* structure or the window instance */
           /* Use Windows's default color as the background of the window */
           wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

           /* Register the window class, and if it fails quit the program */
           if (!RegisterClassEx (&wincl))
                   return 0;

           /* The class is registered, let's create the program*/
           hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               "Matt's Flash Control Program",       /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               544,                 /* The programs width */
               375,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* No menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
                );

           /* Make the window visible on the screen */
           ShowWindow (hwnd, nFunsterStil);

           /* Run the message loop. It will run until GetMessage() returns 0 */
           while (GetMessage (&messages, NULL, 0, 0))
           {
            /* Translate virtual-key messages into character messages */
            TranslateMessage(&messages);
            /* Send message to WindowProcedure */
            DispatchMessage(&messages);
           }

           /* The program return-value is 0 - The value that PostQuitMessage() gave */
           return messages.wParam;
    }


    /*  This function is called by the Windows function DispatchMessage()  */

    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
     switch (message)                  /* handle the messages */
     {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }
//</Initialise Windows module> 

//<Initialise serial port>    
            HANDLE hSerial;
            hSerial = CreateFile("COM1",
            //Since I will only be writing to the port, I have not included GENERIC_READ below
            GENERIC_WRITE,
            0,
            0,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            0);
            if(hSerial==INVALID_HANDLE_VALUE){
            if(GetLastError()==ERROR_FILE_NOT_FOUND){
            //serial port does not exist. Inform user.
            }
            //some other error occurred. Inform user.
            }
//</Initialise serial port>

//<Set serial port parameters>
// I HAVE NOT MANAGED TO GET THIS PART OF THE CODE TO COMPILE SUCCESSFULLY...
// The error message produced is that dcbSerial is undeclared...
/*
       DCB dcbSerialParams = {0};
       dcbSerial.DCBlength=sizeof(dcbSerialParams);
       if (!GetCommState(hSerial, &dcbSerialParams))
       {
        //error getting state
       }
       dcbSerialParams.BaudRate=CBR_19200;
       dcbSerialParams.ByteSize=8;
       dcbSerialParams.StopBits=ONESTOPBIT;
       dcbSerialParams.Parity=NOPARITY;
       if(!SetCommState(hSerial, &dcbSerialParams))
       {
        //error setting serial port state
       }
*/       
//</Set serial port parameters>

//<Avoid timeout data hang>
         COMMTIMEOUTS timeouts={0};
         timeouts.ReadIntervalTimeout=50;
         timeouts.ReadTotalTimeoutConstant=50;
         timeouts.ReadTotalTimeoutMultiplier=10;
         timeouts.WriteTotalTimeoutConstant=50;
         timeouts.WriteTotalTimeoutMultiplier=10;
         if(!SetCommTimeouts(hSerial, &timeouts)){
         //error occurred. Inform user
         }
//</Avoid timeout data hang>

//<Execute flash>
       char szBuff[1] = {2};
       DWORD dwNumberOfBytesToWrite = 2;
       if(!WriteFile(hSerial, szBuff, 1, &dwNumberOfBytesToWrite, NULL))
       {
        //error occurred. Inform user
       }
       
       
//</Execute flash>


//<Close serial port>
        CloseHandle(hSerial);
//</Close serial port>

    return 0;
}
Member Avatar for CaptainProg

I am going to try to break this question down as that is rather a lot of code. First, this is my initial piece of code I am struggling with:

//<Set serial port parameters>

       DCB dcbSerialParams = {0};
       dcbSerial.DCBlength=sizeof(dcbSerialParams);
       if (!GetCommState(hSerial, &dcbSerialParams))
       {
        //error getting state
       }
       dcbSerialParams.BaudRate=CBR_19200;
       dcbSerialParams.ByteSize=8;
       dcbSerialParams.StopBits=ONESTOPBIT;
       dcbSerialParams.Parity=NOPARITY;
       if(!SetCommState(hSerial, &dcbSerialParams))
       {
        //error setting serial port state
       }
     
//</Set serial port parameters>

It was provided by the PDF linked above, however it does not compile. Why is this? The error message says "`dcbSerial' undeclared (first use this function)"

I think it's a typo made by the author, as DCBlength is actually a member of the DCB struct (see http://msdn.microsoft.com/en-us/library/aa363214(v=vs.85).aspx). The author mentions that giving the struct it's own length is a quirk. It's probably meant to be dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

Member Avatar for CaptainProg

Thanks - yes, I did notice this in the end. The error it threw up I assumed was something I had done wrong, but actually when I look at it is kind of obvious.

I have (sort of) solved the problem. When the serial port is initialised, the LED actually lights up (I don't actually have to send the command, just initialise the port). So what I'm doing is when I want to flash the LED, simply to initialise and uninitialise the serial port. I can't get the latter bits of code to compile so this seems to be the only solution. It does the job, but in a very botched way...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.