views:

551

answers:

5

Problem: I have a hand held device that scans those graphic color barcodes on all packaging. There is a track device that I can use that will slide the device automatically. This track device functions by taking ascii code through a serial port. I need to get this thing to work in FileMaker on a Mac. So no terminal programs, etc...

What I've got so far: I bought a Keyspan USB/Serial adapter. Using a program called ZTerm I was successful in sending commands to the device. Example: "C,7^M^J"

I was also able to do the same thing in Terminal using this command: screen /dev/tty.KeySerial1 57600 and then type in the same command above(but when I typed in I just hit Control-M and Control-J for the carriage return and line feed)

Now I'm writing a plug-in for FileMaker(in C++ of course). I want to get what I did above happen in C++ so when I install that plug-in in FileMaker I can just call one of those functions and have the whole process take place right there.

I'm able to connect to the device, but I can't talk to it. It is not responding to anything.

I've tried connecting to the device(successfully) using these:

FILE *comport;
if ((comport = fopen("/dev/tty.KeySerial1", "w")) == NULL){...}

and

int fd;
fd = open("/dev/tty.KeySerial1", O_RDWR | O_NOCTTY | O_NDELAY);

This is what I've tried so far in way of talking to the device:

fputs ("C,7^M^J",comport);

or

fprintf(comport,"C,7^M^J");

or

char buffer[] = { 'C' , ',' , '7' , '^' , 'M' , '^' , 'J' };
fwrite (buffer , 1 , sizeof(buffer) , comport );

or

fwrite('C,7^M^J', 1, 1, comport);

Questions: When I connected to the device from Terminal and using ZTerm, I was able to set my baud rate of 57600. I think that may be why it isn't responding here. But I don't know how to do it here.... Does any one know how to do that? I tried this, but it didn't work:

comport->BaudRate = 57600;

There are a lot of class solutions out there but they all call these include files like termios.h and stdio.h. I don't have these and, for whatever reason, I can't find them to download. I've downloaded a few examples but there are like 20 files in them and they're all calling other files I can't find(like the ones listed above). Do I need to find these and if so where? I just don't know enough about C++ Is there a website where I can download libraries??

Another solution might be to put those terminal commands in C++. Is there a way to do that?

So this has been driving me crazy. I'm not a C++ guy, I only know basic programming concepts. Is anyone out there a C++ expert? I ideally I'd like this to just work using functions I already have, like those fwrite, fputs stuff. Thanks!

+4  A: 

Sending a ^ and then a M doesn't send control-M, thats just the way you write it, to send a control character the easiest way is to just use the ascii control code.

ps. ^M is carriage return ie "\r" and ^J is linefeed "\n"

edit: Probably more than you will (hopefully) ever need to know - but read The Serial Port Howto before going any further.

Martin Beckett
A: 

Are you sure you've installed all the compiler tools properly? On my OS X 10.5.8 Mac, termios.h and stdio.h are right there under /usr/include, just as I'd expect. The code you've already found for serial port programming on other Unix variants should only require minor changes (if any) to work on a Mac. Can you tell us a bit more about what you've tried, and what went wrong?

mgb also has a good point about how the control characters need to be represented.

Jim Lewis
+1  A: 

This isn't a C++ question. You're asking how to interact with the TTY driver to set teh baud rate. The fact that you're opening the file under /dev tells me that you're on a unix derivative, so the relevant man page to read on a linux system is "man 3 termios".

Basically, you use the open() variant above, and pass the file descriptor to tcsetattr/tcgetattr.

Andy Ross
A: 

You can set the baud rate with ioctl. Here's a link to an example.

Mark Ransom
There are no portable TTY ioctl APIs, unfortunately. It's much better to use the POSIX API instead. c.f. termios, tcsetattr, et. al.
Andy Ross
A: 

You don't specify which Unix you are using, so below I'm posting some Linux production code I use.

Pleae note below code is a class method so ignore any external (ie undeclared) references.

Steps are as follows -

Configure your termio structure, this is where you set any needed flags etc (ie the step you accomplished using zterm. The termio settings below configure the port to 8 databits, 1 stopbit and no parity (8-n-1). Also the port will be in "raw" (as opposed to cooked) mode so its a character stream, text isn't framed into lines etc The baud constants match the actual value, ie for 56700 baud you use "57600".

The timing parameters mean that characters are returned from the device as soon as they are available.

Once you have your termainal parameters set, you open the device (using POSIX open()), and then can use tcgetattr/tcsetattr to configure the device via the fd.

At this point you can read/write to the device using the read()/write() system calls.

Note that in the below example read() will block if no data is available so you may want to use select()/poll() if blocking is undesirable.

Hope that helps.

termios termio    
tcflag_t baud_specifier;

    //reset device state...
    memset (&termio, 0, sizeof (termios));
    read_buffer.clear();

    //get our boad rate...
    if (!(baud_specifier = baud_constant (baud))) {
     ostringstream txt;
     txt << "invalid baud - " << baud;
     device_status_msg = txt.str();
     status = false;

     return (true);
    }


    //configure device state...
    termio.c_cflag = baud_specifier | CS8 | CLOCAL | CREAD;

    //do we want handshaking?
    if (rtscts) {
     termio.c_cflag |= CRTSCTS;
    }

    termio.c_iflag = IGNPAR;
    termio.c_oflag = 0;
    termio.c_lflag = 0;

    //com port timing, no wait between characters and read unblocks as soon as there is a character
    termio.c_cc[VTIME]    = 0;
    termio.c_cc[VMIN]     = 0;

    //open device...
    if ((fd = open (device.c_str(), O_RDWR | O_NOCTTY)) == -1) {

     ostringstream txt;
     txt << "open(\"" << device << "\") failed with " << errno << " - "
         << std_error_msg (errno);
     device_status_msg = txt.str();
     status = false;

     return (true);
    }

    //keep a copy of curret device state...
    if (tcgetattr (fd, &old_termio) == -1) {

     ostringstream txt;
     txt << "tcgetattr() failed with " << errno << " - " << std_error_msg (errno);
     device_status_msg = txt.str();
     status = false;

     return (true);
    }

    //flush any unwanted bytes
    if (tcflush (fd, TCIOFLUSH) == -1) {

     ostringstream txt;
     txt << "tcflush() failed with " << errno << " - " << std_error_msg (errno);
     device_status_msg = txt.str();
     status = false;

     return (true);
    }

    //apply our device config...
    if (tcsetattr (fd, TCSANOW, &termio) == -1) {

     ostringstream txt;
     txt << "tcsetattr() failed with " << errno << " - " << std_error_msg (errno);
     device_status_msg = txt.str();
     status = false;

     return (true);
    }

    node_log_f ("successfully initialised device %s at %i baud", "open_device()",
                device.c_str(), baud);

    status = true;
    return (true);
}
Hayman