views:

420

answers:

5

Humbling expierence here and I think this one will make a fool of me, but...I'm trying to convert an ancient cash register program to .net. Conquered everything else, but I can't pop open the cash register. Its connected to COM1, you are supposed to send a "trigger" text down COM1 that will cause the register to open.

Here is the .net code.

    MsgBox("Opening Drawer")

    Dim port As System.IO.Ports.SerialPort
    port = New System.IO.Ports.SerialPort("Com1")

    port.PortName = "COM1"
    port.BaudRate = 9600
    port.Parity = IO.Ports.Parity.None
    port.DataBits = 8
    port.StopBits = IO.Ports.StopBits.One
    'port.Handshake = IO.Ports.Handshake.RequestToSend
    port.RtsEnable = True
    'port.DtrEnable = True
    port.Open()
    If port.IsOpen Then

        'MsgBox("Attempt 1")
        port.Write("@@@@@@@@@@@@@@@@@@@@")
        MsgBox("Signal Sent: " & Chr(65))
    Else
        MsgBox("Port is not open")
    End If

    port.Close()
    MsgBox("Pop, durn it!")

I get msgboxes "Signal Sent", "Done Pop Drawer"

Dang thing, just won't pop. It's an MS-Cash Drawer (EP125KC). Definitely connected to COM1, definitely has power. Chr(65) is the old code used to pop drawer and it works:

Open drawerComPort For Output Access Write As #1
Print #1, Chr$(65); "A";
Close #1

NOTE: The above code worked successfully. The root problem was caused by a reveresed power cord (negative was on the wrong side).

Thanks for all the help guys!

A: 

If I remember my very rusty BASIC.

Print #1, Chr$(65); "A";

means print to port1 the character 65 followed by the string "A", Now the character 65 is 'A', so this looks to me like you should be sending "AA" to port1

port.Write("AA");

or alternately,

port.Write(new byte[]{65,'A'}, 0, 2);
John Knoeller
+1  A: 

You've set your handshake to None but the cash drawer probably has its own idea. Also set DtrEnable to True. Chr(65) is the ASCII code for an "A", your VB code suggests the real command is "AA".

The manual documents that the cash drawer auto-tunes its baudrate. It recommends sending at least 20 @ characters. And that the real command is Ctrl+G (Chr(7)). The "AA" command might have worked previously due to a baudrate mismatch. Perhaps.

Hans Passant
Can you elaborate, is that 20 @ chars or 20 ctrl+g...handshake is now set to RequestToSend.
Markus
20 @ chars, 1 Ctrl+G. Do you have a manual?
Hans Passant
Unfortunately no... if you have a link to one please share
Markus
Link: http://www.retrevo.com/search/v2/jsp/mytrevo/myTrevo.jsp?page=man
Hans Passant
Set me on the right track with the manual and the baudrate mismatch problem. Thanks nobugz!
Markus
A: 

Are you sure you're supposed to send out this code? I would have always thought that the code is prefixed by ESC i.e. 0x1b hexadecimal...for cash drawers...

"\x1bA"

Interesting that double 'A' is used...oh well... :)

Edit: After thinking about this I realized there is another way of doing it, read on... I have modified your original BASIC code with a bit of bullet-proofing...save it to opendrawer.bas

Sub OpenDrawer()
drawerComPort = "COM1"
Open drawerComPort For Output Access Write As #1
REM ADDED ERROR HANDLING
ON ERROR GOTO ErrHandler
Print #1, Chr$(65); "A";
Close #1
print "Drawer Ok"
OpenDrawer_Exit:
On Error Goto 0
Exit Sub
ErrHandler:
print "Oops, Write Failed"
Goto OpenDrawer_Exit
End Sub

REM The Main....
OpenDrawer

Download the old QB4.5 MS-Quick Basic compiler, and compile that to an executable, into opendrawer.exe, the QB4.5 can be found here. Now, the onus is on you to make this bulletproof, i.e. what happens if writing to COM1 fails, issue a message like in the example BASIC code I modified

Then you can use the System.Diagnostics.Process to shell out using a hidden window

    public class TestDrawer
    {
        private StringBuilder sbRedirectedOutput = new StringBuilder();
        public string OutputData
        {
            get { return this.sbRedirectedOutput.ToString(); }
        }
        public void Run()
        {
            System.Diagnostics.ProcessStartInfo ps = new System.Diagnostics.ProcessStartInfo();
            ps.FileName = "opendrawer";
            ps.ErrorDialog = false;
            ps.CreateNoWindow = true;
            ps.UseShellExecute = false;
            ps.RedirectStandardOutput = true;
            ps.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

            using (System.Diagnostics.Process proc = new System.Diagnostics.Process())
            {
                proc.StartInfo = ps;
                proc.Exited += new EventHandler(proc_Exited);
                proc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(proc_OutputDataReceived);
                proc.Start();
                proc.WaitForExit();
                proc.BeginOutputReadLine();
                while (!proc.HasExited) ;
            }
        }

        void proc_Exited(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("proc_Exited: Process Ended");
            if (this.sbRedirectedOutput.ToString().IndexOf("Oops, write failed") > -1){
               MessageBox.Show(this, "Error in opening Cash Drawer");
            }
            if (this.sbRedirectedOutput.ToString().IndexOf("Drawer Ok") > -1){
               MessageBox.Show(this, "Drawer Ok");
            }
        }

        void proc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (e.Data != null) this.sbRedirectedOutput.Append(e.Data + Environment.NewLine);
            //System.Diagnostics.Debug.WriteLine("proc_OutputDataReceived: Data: " + e.Data);
        }

The process shells out to a hidden window and all output is redirected and handled in the event handler...that should do the trick. Notice, how the redirected output goes into the sbRedirectedOutput (a StringBuilder instance). In the proc_ProcExited event handler, it checks the sbRedirectedOutput for the message 'Oops Write failed' which would be issued from the QB4.5 program.

Be aware, that you may need to include the QB4.5's run-time library in the same directory...not 100% sure...it's being years...

What do you think?

Hope this helps, Best regards, Tom.

tommieb75
A: 

It might be sending Unicode 65, which would be 0065, which would not end well.

Just a thought, can you try sending a raw int?

Guvante
A: 

I dont use .net, but is the port buffered? do you need to send a flush/fflush()?

Mobs
SerialPort.Flush Method - Sends any data waiting in the send buffer of this SerialPort and clears the buffer. -Namespace: System.IO.Ports - http://msdn.microsoft.com/en-us/library/dd169859.aspx
Mobs