Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Making an application using MSComm more responsive 1

Status
Not open for further replies.

steve4king

IS-IT--Management
Feb 6, 2007
154
0
0
US
I've worked with a few point of sale applications, and in a few rare cases seen where a cheap USB-Serial converter would cause occasional lockups when attempting to send messages to a display pole.

I've recently had a few users complain about locks or long delays which have been attributed to display pole communications. No converters in this case.
So, I'm going back through one of these and trying to determine how I can make the process faster/more robust.

We're using MSComm32, (OPOS is tempting, but thinking it's probably unnecessary)
Assuming there is an anomaly where communication runs into an issue or delay.. Will the OnComm event pick that up? (Being unfamiliar here, it looks like OnComm is usually used for detecting receive buffer changes moreso than error handling..)

Is it possible to push the display update into a new thread so that my application doesn't have to wait for it? If not, just setting a 1 second timeout would probably suffice.. without using a second thread however, I'm not sure how that would be accomplished.

Any thoughts?

Thanks,
-Stephen

 
Just to note, I was able to replicate the locking behavior by mashing the button on this little snippet I stole from MS:

Code:
PUBLIC oform1
      oform1=CREATEOBJECT("form1")
      oform1.NewObject('LV1','OC1')
      oform1.Show
      READ EVENTS
      RETURN

      DEFINE CLASS form1 AS form
         cNextKey = "1_"
         Name = "Form1"
 
		 
         ADD OBJECT cmdExit AS commandbutton WITH ;
            Top = 204, ;
            Left = 276, ;
            Height = 27, ;
            Width = 84, ;
            Caption = "E\<xit"

         ADD OBJECT cmdAddLVClass AS commandbutton WITH ;
            Top = 204, ;
            Left = 130, ;
            Height = 27, ;
            Width = 136, ;
            Caption = "Add Listview Subclass"

         PROCEDURE Destroy
            CLEAR EVENTS
         ENDPROC

         PROCEDURE cmdExit.Click
            thisform.release()
         ENDPROC

         PROCEDURE cmdAddLVClass.Click
            Thisform.SetLVProps()
         ENDPROC

         PROCEDURE SetLVProps
            thisform.setall('enabled', .F.,'commandbutton')
            WITH thisform.LV1
               	.Commport = 6
               	.Settings = "9600,N,8,1" 
               	.portOpen=.T.
               	.OutBufferCount = 0
               	.Sthreshold = 1
               	.output = CHR(12)
               	.Output = ("Line 1")+ chr(13)
               	.PortOpen = .F.
            ENDWITH
            thisform.setall('enabled', .T.,'commandbutton')
         ENDPROC
      ENDDEFINE

      DEFINE class OC1 as olecontrol
         OleClass = "MSCOMMLib.MSComm"
      ENDDEFINE

After a 90sec lock. No error was displayed and the port was left open/locked. (.portopen shows false, but when attempting to open, it tells me it's already open)
I know I might be able to get around the open port issue by moving the portopen/close to a higher scope right before/after form show.. but I'm mostly concerned with the lockup itself at this stage.
 
Have you included "_VFP.AUTOYIELD = .F." in your app? You may need to.
Also, I've had to use INKEY() and DOEVENTS() to sometimes force events, or more specifically, get VFP to respond faster to events.

For example, in my OnComm event:
Code:
THIS.OUTPUT = CHR(10)   &&... NewLine
DOEVENTS
x = INKEY(.1, 'HM')



-Dave Summers-
[cheers]
Even more Fox stuff at:
 
>I know I might be able to get around the open port issue by moving the portopen/close to a higher scope right before/after form show.. but I'm mostly concerned with the lockup itself at this stage.
I'd see that even higher than on the form level, on the appstart level. You get a more stable port, if you don't open/close it all the time.

It seems like you lock yourself, when you don't wait sufficiently for the port opening or closing. Only one process can open a port at one time and when you open a port while it's not yet closed and flushed input/output buffers, you might run into this lock situation.

Dave has put a finger on _VFP.AUTOYIELD. Read about it, and indeed setting it .T. would rather make VFP handle Olecontrol events more often. But you may try both settings, some ActiveX controls work best with it on, some best with it off. I'd also suggest DOEVENTS FORCE before and after each change of .PortOpen.

I'm currently reimplementing a feature of an application controlling electronic scales via serial ports, discovering them, sending commands and retrieving their responses (mostly the current weight, of course). I'm moving away from CommTools/Foxpro towards a C# windows service for that matter and just open ports once at each system boot. I'm close to finishing this service and it's now working fine for hours with only once initing each port. Only at stations working with a single port and a MUX switch device, I need to close and open COM1, to send a command to the MUX to switch to another end port, but also this is working quite well and as it's done on the Windows services level it's not even depending on application stability, merely on Windows stability, and that is very good since at least NT or XP.

I don't suggest you go the same route, but indeed if you only have this one port setting, it should be sufficient to open the port when your application starts. To be able to do this with the MSComm OCX control I'd put this on a hidden non modal form you start when your app starts and store a reference to the control itself to a _screen or goApp property.

Actually the reason for my reimplementation of the serial port scales feature is, that on more and more stations (win7 netbooks) commtools reproducibly reports "NO_PORT" when opening a port, where there still is a port seen in Device Manager. dotNET doesn't fail with this.

Unfortunately that software - as many things I do - is closed source for a customer, but this info surely is not under NDA.

Bye, Olaf.
 
Thanks guys, very helpful.

Olaf, I was curious about that: Best practices whether it was OK to just leave the port open for an extended period of time. (possibly days)
 
"...OK to just leave the port open for an extended period of time. (possibly days) "
In short, yes. Unlike sometimes flaky network connections, it is probably more reliable to leave COM connections open rather than try to close and reopen.
The snippet of code I showed you comes from an app that remains active for weeks at a time.


-Dave Summers-
[cheers]
Even more Fox stuff at:
 
I can confirm from the negative experience. As I said the main reason was port opening leading to errors. And my recent experience with the stability of a port kept opened is confirming what Dave says.

Consider it's an exclusive access to the port, anyway. It would be a bad thing, if other software would need access to the same port/device, too. But hardwarewise there are no cons. Many things operate permanently, so why should a serial port not operate permanently?

In my example I'm using the DataRecieved event (which compares to MSCOMM.OnComm) and at each end of retreiving a weight I send a new "print" comand, so the COM port is not only permanently open, it's permanently transferring data back and forth, determining the current weight. It's stable, because it's local and perfors slow and without any mechanical parts. But even that's not a criteria, because harddrives can work 24/7, too with their readwritehead and platters spinning all the time. Even at higher rpm for permanent use server drives.

As said, the only con reason is, anther application also needs to be able to address the same port and it's device.

Bye, Olaf.
 
Thanks for the suggestions.
Huge improvement in product speed and I expect stability, since I cannot crash it anymore.

Ended up tying it to a main workscreen, load creates a public hidden form, attaches commctl, and connects the port. Unload disconnects and releases.

I didn't find any noticeable difference with autoyield either way.

Doevents force: "Pauses Visual FoxPro code execution until a Windows event occurs, such as moving the mouse."
I don't see how this would be beneficial prior/post opening or closing a port..

Thanks again,
-Stephen
 
Oh, for devices unidirectional such as this, is there any way to determine whether or not a device is receiving what I'm sending?
I can tell if a port exists or not easily enough. However, when sending to an unused port the buffer doesn't fill up it doesn't look possible.
 
>Doevents force: "Pauses Visual FoxPro code execution until a Windows event occurs, such as moving the mouse."
This description of the help is totally crippled and meaningless.

DOEVENTS does not wait for events to occur, but it let's windows do events, if there is something in the queue. You know about Window preemptive multitaksing principles?
When you switch OpenPort from .T. to .F. or vice vera, you are creating a windows event and that only can happen, when VFP's thread gives back control to the OS to let other tasks work, eg the one(s) responsible for OLE, and the hardware layer, serial ports, memory, whatever involved in this.

And so you actually cause many events to be added to an OS event queue, and it's not wrong, if you then DOEVENTS FORCE to enforce them to happen, before you continue.

DOEVENT also is making your app itself response, while in a scan..endscan loop, helps to let IE load pages faster and get into readystate=4, enforces a createobject("word.application") to create a fully funcional object reference (if you don't DOEVENTS after createobject, since Office 2007 you get a fast response with a half baked object reference and when addressing eg documents often get errors the subobjects don't exist. DOEVENTS has many good cases.

In regard of finding out, if your data arrives, that's not possible, no.

I can tell you stories: In case of my scales feature we defined a set of 10 serial port settings I try and test, if a scale eacts to a print command with a valid response and if it tares at a tare command. I can' ask the device for it's port setting, because I need a connection with valid settings before I can communicate with a scale. Also I can't ask the users to specify scales port settings, as they don't know how to read, even if they would, it's a complicated menu you need to operate with just two keys and it's not very intuitive. Also I control MUX switches, which don't respond at all. I send a command to switch to a certain output port several times, just to make sure.

Aside of that, when a connection is established, the only thing, that helps is, if the device reacts to some input with output, so you can see if the connection works. If there is no such command the device offers, you have to output and pray. Of course in case of a display you can easily test and verify be seeing yourself and get a feeling of the reliability by tests. Otherwise look for USB devices, serial ports are a dying species. It's just hardly payable to replace 100s of scales each worth thousands of euros.

Bye, Olaf.
 
You should only open a port once, best at the beginning of the application as others have already posted. We take weather readings all day long, every 15 seconds and never close the ports until we exit.

There are other communication programs with more capabilities such as up to 256 ports. MSCOMM is limited to 16 unless you hack the control. I use Marshallsoft but give the users the ability to use MSComm instead with a checkbox if they need to. My application will listen on one port, and send info out to another device on another port all day long and as long as the port numbers are under 16 we can use either communication program.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top