Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Kludging the serial port

by Aighearach
on Oct 08, 2001 at 18:11 UTC ( #117455=perlquestion: print w/replies, xml ) Need Help??
Aighearach has asked for the wisdom of the Perl Monks concerning the following question:

I've been programming a CashCode brand bill validator (excellent product, much better than Mars), and now I'm trying to find something that doesn't suck to replace an ugly kludge.

The bill acceptor has a "serial" interface, which is of course not a PC serial port but rather some sort of specialty interface. I'm using a converter module that claims to convert it to RS232. Which it mostly does. However, that alone doesn't allow me to control the unit. There is a handshaking process involved, and in their infinite wisdom, the converter requires me to drop (0V) and raise(5V) pin 3, which is normally RD(aka RX). Unfortunately, I can't just swap, for example, RD and RTS, and use RTS for the acking, because it requires normal functioning on RD, also. So, the sollution I have found is to tie RD and RTS together. This allows me to force RD high or low by playing with RTS, and still allows me to receive data normally on RD.

I'm really unhappy with this sollution, it is an ugly hardware hack, which is going to require me to build/buy a custom connector for each unit. Also, normally RD has 0V to -5V, and with RTS I'm pushing it from 0V to +5V. I have no idea if that is safe for the hardware in the long term. So my question is, does anybody know of a way in software to pull RD low? Currently I'm using Device::SerialPort, but I'm not set on doing it that way.
Snazzy tagline here

Replies are listed 'Best First'.
(jcwren) Re: Kludging the serial port
by jcwren (Prior) on Oct 08, 2001 at 19:43 UTC

    RD cannot be controlled in software. It is a receive only input into the serial shift register. RD does not normally have a range of only 0 to -5V, unless it is disfunctional. To be RS232C compliant, pins must be no greater than +/- 30V, and no less than +/- 3V. Many level converters will treat 0V as if it were a negative voltage, but that is not RS232C compliant, nor is it *any* guarantee that it will work from system to system.

    Real RS232 drivers are tolerant of being shorted together indefinitely, and the recievers being driven at +30V or -30V indefinitely. Most decent ones have 15KV human-body-model ESD protection. Proper RS232 is capable of sourcing/sinking up to 10 milliamps per pin, so shorting a driver at +5V to a driver at -5V won't damage the system (nor will it do anything useful). Inputs typically have pullups or pulldowns to the voltage rails to hold them in their idle condition. This prevents an unplugged cable from looking like DTR, etc is still asserted. This is most likely why you see a negative voltage on the input.

    I'd like to see the schematic for this interface, because what you describe makes no sense (not what you typed, but what the product is expecting).


    e-mail jcwren
      Thank you, I am less worried about my sollution's safety now. The interface is (sortof) described at CashCode's website. PDF only. There are 4 manuals, each manages to describe part of the protocol. Some of them claim that the device supports 600 baud, others that it senses 1200 or 9600. My unit only works at 600. I don't have any specs on the "serial" to RS232 converter, as that would require spending an extra $500 on a "developers kit" from Happ Controls. I used the timings described in CashCode's MAN-CCS.pdf. Basically, they have a line labelled SEND, which they want me to play with when they throw their INTERUPT line. The interupt is tied to one of the handshake lines, but is irrelevant to me, as if SEND is in the correct state for the bill validator to be active and send a message, then I can just read the incoming data, and know by that when to respond, even if I turn off handshaking in my software. I used an RS232 breakout box to toggle lines until I found the SEND. I might not have found it correctly; I found I could also toggle one of the handshake lines from the validator side, and it would partially respond, but only with RD could I get it to give me the full documented behavior. And I couldn't think of another way to toggle it in software than tying it to RTS. (the other potential source, DTR, is the ACCEPT ENABLE line from the docs)

      I agree it makes no sense, but with the following code the whole thing works. (without the hardware hack, you put a bill in and it just stays in ESCROW position)

      use strict; require 5.006; use warnings; use Device::SerialPort; use Time::HiRes qw/ usleep /; my $port = shift @ARGV; $port ||= '/dev/validator' if -e '/dev/validator'; $port ||= '/dev/ttyS1' if -e '/dev/ttyS1'; $port ||= '/dev/ttyS0' if -e '/dev/ttyS0'; # validator commands my ( %v_bills, %v_status ); $v_status{pack('H*','89')} = 'VEND'; $v_status{pack('H*','8a')} = 'RETURNED'; $v_status{pack('H*','8b')} = 'REJECT'; $v_status{pack('H*','8c')} = 'FAILURE'; $v_status{pack('H*','8d')} = 'STACKER FULL'; $v_status{pack('H*','8e')} = 'LRC REMOVED'; $v_status{pack('H*','8f')} = 'LRC ATTACHED'; $v_bills{pack('H*','81')} = 1; # $1 inserted $v_bills{pack('H*','82')} = 2; $v_bills{pack('H*','83')} = 5; $v_bills{pack('H*','84')} = 10; $v_bills{pack('H*','85')} = 20; # what about model 1100, when it gets a $50 or $100? Not in the chart +:( $PortObj->baudrate( $baud ); $PortObj->parity("none"); $PortObj->databits(8); $PortObj->stopbits(1); $PortObj->datatype('raw'); $PortObj->write_settings(); print STDERR "$0 ($$) started at ",scalar localtime(), "\n"; # always send an ack to start, in case there is an event in the valida +tor's queue, or a half processed event ack(); my $last = time; while (1) { my ($count, $data) = $PortObj->read( 1024 ); if ( $count and defined $data ) { foreach my $byte ( split //, $data ) { if ( exists $v_bills{$byte} ) { printf "saw a \$%s dollar bill\n", $v_bills{$byte}; if ( $enabled ) { accept_bill(); } else { reject_bill(); } } elsif ( exists $v_status{$byte} ) { printf "saw status event %s\n", $v_status{$byte}; ack(); } else { my $hex = unpack "H*", $byte; my $bin = unpack( "B*", $byte ); $bin =~ s/(.{8})/$1 /g; # seperate the bytes please printf "UNKNOWN: hex: %s bin: %s\n", $hex, $bin; } } } else { pause( 50_000 ); # because the $PortObj->read is nonblocking, we d +on't want to loop too tight. so pause 50ms if a read fails. } } sub ack { $PortObj->rts_active( 0 ); pause( $rts_timing ); $PortObj->rts_active( 1 ); } sub accept_bill { ack(); } sub reject_bill { $PortObj->rts_active( 0 ); $PortObj->dtr_active( 0 ); pause( $rts_timing ); ack(); } sub pause { my $time = shift || 500_000; # micro seconds usleep( $time ); return 1; }
      Of course, the useful version does more than just print to the screen that money was inserted ;)
      Snazzy tagline here
Re: Kludging the serial port
by Dr. Mu (Hermit) on Oct 09, 2001 at 04:40 UTC
    I looked at their docs. The "send" and "data" lines are separate here, and of a polarity that should render them useful with a normal RS232 converter. By "normal", I mean one that converts outgoing CMOS 0V to (+3 to +12V) and CMOS +5V to (-3 to -12V), and vice-versa for incoming RS232 lines. This is to say, it inverts in both directions. This needs to be done for all the signals you use. If it doesn't do this, you're not getting your money's worth, and I'd get a different converter or build one using a Maxim MAX232 or somesuch IC.

    Once you have a proper converter, the rest is easy. Pin 2 on your PC's DB9 should map from the note scanner's "data" line. It's easiest if the "send" line maps to one of the handshake lines the PC can control directly, but if it maps to the PC's TX line (pin 3) that's okay too. You just need to send the changer a pulsed BREAK for a period long enough to meet their timing requirements. This is done with: $PortObj->pulse_break_on($milliseconds);
    What this does is raise the RS232 TX line (pin 3) from -10V, say, to +10V for a period you specify. The converter, by inverting this, will create a 0V pulse on a normally 5V signal line -- just what the scanner wants. Then all you have to do is check your input buffer for the incoming data byte.

    With all the means available for doing this right, there just isn't any excuse for kludging the hardware in the manner you describe.

      As I found out, if you are interfacing to a PC, you do not need to use anything as fancy as a MAX232. In fact, a plain old 74HCT00 (quad nand gate) will suffice. Simply take PC output connect it to a 22k resistor and tie it to the inputs of one of those gates. The output of that gate will be the RS232 input into your device. Similarly, take the output of your device, tie it to the inputs of another gate and that output will be the input into the PC. This is not fully RS232 compliant but it's awfully cheap and works wonders with PCs.

      Yes and no. Yes, in the docs they are listed as seperate lines. No, that is not the way it is actually working.

      Yes, that appears to be the action of the converter.

      Yes, that would be the logical way for it to be wired, and is quite what I was expecting. But there is not a single unused line that you can cycle to get the desired behavior. Using an RS-232 breakout box, I tried all the lines... only by turning off and restoring RD would the hardware respond in the way that is described for when the SEND line is toggled.

      $PortObj->pulse_break_on() doesn't do anything for me. First of all, as the docs specify, you can't get exact timing out of it. Second, that plays with TD (pin 2) not RD (pin 3), and the hardware doesn't blink. Actually, I wrote a strober to try all the pulse methods before I tried manually playing with the voltages via breakout box. Closest I can get that way is to throw ACCEPT_ENABLE(DTR) around, which makes it burp but not finish processing any events or state changes.

      With all the means available for doing this right, there just isn't any excuse for kludging the hardware in the manner you describe.
      Yes, and considering your sollution contains errors, and also doesn't work at all, there is even less excuse for your attitude than for my kludge. If I thought I had the ideal sollution, I would have posted in CUFP instead of Seekers. On the bright side, since it's for my own company I only need it to accept the customers money and credit them; nobody is going to ask what it's "excuse" for working is.
      Snazzy tagline here
        Sorry if my tone offended. It's just that I've been burned enough times by hardware kludges, I tend to mount the soapbox when I see others toying with the same fate. Especially since you indicate it's not a one-off project, I still maintain it's worth the time to figure out what's going on and get it right.

        I confess confusion now regarding the separation/non-separation of the RD and SEND lines. I'd be happy to provide more assistance if I knew more about the circuitry of your RS232 converter. Unfortunately, this goes outside the realm of Perl, so this probably isn't the best forum to continue the discussion. Perhaps you could message me on the Chatterbox with your email address, and we could continue there.

Re: Kludging the serial port
by John M. Dlugosz (Monsignor) on Oct 08, 2001 at 21:05 UTC
    What kind of specialty interface? Maybe it's not something they made up, but another RS standard. RS 4something is also common for industrial stuff, because it has better noise rejection and longer cable runs.

    If it is that, you might buy canned hardware to do the trick, and find writups of the software issues already solved.

      It's supposed to be fully compatible with the Mars (the candy and vending company) Serial Interface. I am using canned hardware to convert it to RS-232; but it seems to have a bug in that I had to use this kludge to make it work.
      Snazzy tagline here

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://117455]
Approved by root
and the rats come out to play...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (7)
As of 2018-06-18 22:16 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (111 votes). Check out past polls.