• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 752
  • Last Modified:

Writing too fast to COM port?

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
showbix
Asked:
showbix
  • 4
  • 3
  • 2
  • +3
1 Solution
 
itsmeandnobodyelseCommented:
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
 
itsmeandnobodyelseCommented:
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
 
CayceCommented:
Can you post some of the code?

Regards, Cayce
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
showbixAuthor Commented:
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
 
showbixAuthor Commented:
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
 
KurtVonCommented:
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
 
showbixAuthor Commented:
Hi Alex.
Is there any means to contact you by email or IM?
Does this allowed in EE?
0
 
CayceCommented:
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
 
itsmeandnobodyelseCommented:
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
 
grg99Commented:
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
 
itsmeandnobodyelseCommented:
>> 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
 
guntherothkCommented:
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
 
grg99Commented:

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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

  • 4
  • 3
  • 2
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now