Solved

Writing too fast to COM port?

Posted on 2004-04-12
13
728 Views
Last Modified: 2013-11-25
I have an application developed in Turbo C++ targeted for Win16 environment. There are some problems arised when running it :-

1. It will truncate some printing if I run the program (without debugging mode) but if I run the program by putting several breakpoints in debugging mode, it will print all the output successfully.
It seems like if I put 'PAUSE' in some places, it prints good. I suspect the problem lies at WriteComm API that I used. It seems that the process of writing data to com port is to fast to handle by the printer and that makes the printer unable to catch the data and print correctly.
Well, I do need experts opinion on this matter.
0
Comment
Question by:showbix
  • 4
  • 3
  • 2
  • +3
13 Comments
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10805340
You may update your SendMsg function to that

    void SendMsg(const char* msg, int lenMsg)
    {
           for (int i = 0; i < lenMsg; i++)
           {
                 WriteComm(hComm, msg[i], 1);
                 Sleep(1);     // wait one millisecond
           }
    }

You may increase Sleep argument if it is still too fast.

Note, the second argument of SendMsg. In case you have to send binary data also, you shouldn't use strlen() within SendMsg as strlen() stops at the first zero character.

Regards, Alex
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10805399
If you actually have to write Windows 3.1x programs - very strange as i wrote my last 16-bit application 1994... - you should consider to take MS Visual Studio 1.52c. There, you have MFC (Microsoft Foundation Classes) where you don't need to write directly to printer devices but may use Win GDI functions to print to any printer defined in the Windows print settings. Also consider, that even in a Win311 environment there is a Win32s subsystem available to write 32-bit applications and not to have to care about 16 bit pointers and segmentation...

Regards, Alex
0
 
LVL 9

Expert Comment

by:Cayce
ID: 10805431
Can you post some of the code?

Regards, Cayce
0
 

Author Comment

by:showbix
ID: 10805478
Hi Alex.
I never used the Sleep() function before but I've tried with SetTimer(hWnd, TIMER_ID, 1000, NULL) function. SetTimer() function doesn't help to solve the problem. I will try to use Sleep() afterwards.
Is there any significant differences between Sleep() and SetTimer()?
0
 

Author Comment

by:showbix
ID: 10805518
Hi Cayce.
This is the code.
------------------------------------------------------------------------------------------------------
void SendMsg(char *pMsg)
{
      char *input;
      char sMsg[80]={0};
      int i=0;
      for(i=0;i<2000;i++)
      {
            ;
      }

      WriteComm(hComm, pMsg, strlen(pMsg));
      input = ReadCOMMInput();

}

char *ReadCOMMInput()
{
      char sMsg[80]={0};
      int ret;

      ret = ReadComm(hComm, sMsg, 1024);


      return sMsg;

}

------------------------------------------------------------------------------------------------------
0
 
LVL 11

Expert Comment

by:KurtVon
ID: 10805524
I beleive WriteComm buffers data it gets, so it isn't a matter of sending too fast for the port but overrunning the buffer.  Check the return value and make sure all the data was written, if not all data was written, wait a few milliseconds and then resend the missed stuff.

Hope this helps.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:showbix
ID: 10805553
Hi Alex.
Is there any means to contact you by email or IM?
Does this allowed in EE?
0
 
LVL 9

Expert Comment

by:Cayce
ID: 10805582
void SendMsg(char *pMsg)
{
     char *input;
/*     char sMsg[80]={0};
     int i=0;
     for(i=0;i<2000;i++)
     {
          ;
     }
*/
     short length = strlen(pMsg);
     short pending = length;
     while(pending) {
        pending -= WriteComm(hComm, &pMsg[length - pending], pending);
        Sleep(250);
      }
     input = ReadCOMMInput();
}


// BTW You ReadCOMMInput()  is really screaming for trouble. You're reading into an auto variable then returning it.
// Plus the read buffer is just 80 bytes long, and you're reading up to 1KB.
0
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 75 total points
ID: 10805822
Did you try Sleep() ?

SetTimer is a function that uses the Windows Message Loop to get a WM_TIMER message after the time intervall had elapsed-. Sleep() is much easier - if available. If Sleep() isn't avilable you would have to implement the Timer functionality like that:


// we need a new timer id different from other timers
#define SENDMSG_ID 998

// change your prototype to having initial = TRUE as default
void SendMsg(const char* msg, int lenMsg, BOOL initial = TRUE);

void SendMsg(const char* msg, int lenMsg, BOOL initial)
{
     static char* pszBuffer     = NULL;
     static int     offset           = 0;
     static int     bytesToSend = 0;

     // if we get called from a function and not from message loop
     // we just save the buffer to static variables and wait to get called via WM_TIMER
     if (initial)
     {
         if (pszBuffer != NULL)
         {
               char* psz = new char[bytesToSend + lenMsg];
               memcpy(psz, &pszBuffer[offset], bytesToSend);
               delete [] pszBuffer;
               pszBuffer = psz;
               offset      = 0;
         }
         else
         {
               pszBuffer      = new char[lenMsg];
               offset           = 0;
               bytesToSend = 0;
         }
         memcpy(&pszBuffer[bytesToSend], msg, lenMsg);
         bytesToSend += lenMsg;
         SetTimer(hWnd, SENDMSG_ID, 1, NULL);  // choose a very small time intervall
     }
     else
     {
          WriteComm(hComm, pszBuffer[offset++], 1);
          if (--bytesToSend <= 0)
          {
                delete [] pszBuffer;
                pszBuffer = NULL;
                offset = bytesToSend = 0;
                KillTimer(hWnd,  SENDMSG_ID);
          }
     }
}


And in your WindowsProc:

    ...
    case WM_TIMER:
         if (wParam == SENDMSG_ID)
         {
              // invoke SendMsg
              SendMsg(NULL, 0, false);
              break;    // break message switch
         }
           
>> Is there any means to contact you by email or IM?

You may send any lengthy input files to info@sbsweb.info. However, you should post your code here in EE as there are other experts to help you as well.

As i have no Win3.1 environment nor a  Borland compiler, it cost's me a lot of time to get your sources compiled with my system. And as i have none of your printers nor any intention directly to write to any of my printers, there is no way to get your prog running on my system.

Regards, Alex

0
 
LVL 22

Expert Comment

by:grg99
ID: 10806015
Adding Sleep()'s in random places is a very bad way of trying to fix this problem!

The printer, being mechanical, may take considerably different amounts of time to print different data.

For instance, a bunch of short lines take much longer to print than one long line, as feeding the paper takes
much longer than printing a line of characters.

Also, Sleep()'s effect is somewhat overriden by the OS's buffers and any buffers in the printer.
So some Sleeps() may effectively do nothing, while others may actually speed up the output by giving the OS more time.

The way to fix this is to find out where the characters are getting lost... you may be ignoring any "I AM FULL" messages coming back from the printer.   These are often handled by the printer driver or OS, but maybe you have the wrong print driver, or it has the backchannel handshaking turned off, or it may even be a bad printer cable or one without the backchannel wires in it.

Please look at these other issues before ever thinging of using Sleep() to "fix" the problem.

Regards,



grg99

0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10806226
>> Adding Sleep()'s in random places is a very bad way of trying to fix this problem!

Using Sleep() to slow the output isn't worse than writting directly to a printer device. And it will most likely solve the problem if too much speed and buffer overflow had been the reason. If slowing down works you may look for a better solution like checking error codes and reading printer drivers manuals. Maybe you have to call Sleep() only after an overflow error had occurred and have to rewrite the last buffer after wait.

However, the most simple solution is to use Windows GDI not having to care about printer settings, escape sequences and hand-shakes.

BTW, i have had a device where output had to been slowed to get the final solution. It was a card reader for a big hospital over a 25 milliampere connection. The card reader's price was about 50,000 $, the computer was a VAX 650 double processor using 64 MB RAM. It's price was about 400,000 $ in .... 1984.

Regards, Alex
0
 
LVL 2

Expert Comment

by:guntherothk
ID: 10808479
If you're writing to a com port that is actually going out a serial RS-232 port, your problem might more easily be solved by using either software (XON/XOFF) or hardware (RTS/CTS) flow control. It might also be solved by lowering the baud rate.

Software flow control only works if your data stream is printable characters that don't normally contain the XON or XOFF (control-S and control-Q) characters. Hardware flow control requires a cable that connects the RTS and CTS lines.
0
 
LVL 22

Expert Comment

by:grg99
ID: 10808698

Using Sleep() to slow the output isn't worse than writting directly to a printer device. And it will most likely solve the problem if too much speed and buffer overflow had been the reason.

"solve the problem", no.  Perhaps cover up the problem, for a certain set of data, in one particular font, maybe.
But if the operator changes  the printer font, or changes it to "higher quality" multipass priting, or opens the printer cover to straighten the paper, or undo a paper jam, or if the printer slows down for any other reason, Sleep(1000) isnt going to help.


>If slowing down works you may look for a better solution like checking error codes

YES!       Funny how we usually check for errors only if we get burnt.


However, the most simple solution is to use Windows GDI not having to care about printer settings, escape sequences and hand->shakes.

If the low-level driver is bollixed, or misconfigured, or miswired cable, then all the Windows GDI glop isnt going to help.
You'll just get bitmapped garbage instead of text garbage.


>BTW, i have had a device where output had to been slowed to get the final solution. It was a card reader for a big hospital over a 25 milliampere connection. The card reader's price was about 50,000 $, the computer was a VAX 650 double processor using 64 MB RAM. It's price was about 400,000 $ in .... 1984.

Yes, VAXes were really poor at handling lots of interrupts.  Our local guru had to patch the line-printer driver so the line-printer wouldnt interrupt so much and tie up the $300,000 VAX.

Sometimes you have to slow INPUT devices down so the computer can keep up.  

But that has little to do with this case, where the computer is too fast for the printer.


(How about we just pass a law outlawing anything using RS-232--- I've wasted weeks of my life and forests of paper  getting RS-232 connections to work between PC X and Printer Y, or worse yet, PC X and plotter Y. A $22,000 plotter and it's very picky about what it accepts.


Regards,

grg99

0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Storage devices are generally used to save the data or sometime transfer the data from one computer system to another system. However, sometimes user accidentally erased their important data from the Storage devices. Users have to know how data reco…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn how to successfully create a multiboot device using the SARDU utility on Windows 7. Start the SARDU utility: Change the image directory to wherever you store your ISOs, this will prevent you from having 2 copies of an ISO wit…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now