Serial port communication (Tiger vs Leopard)

Discussion in 'Mac Programming' started by idelovski, Aug 20, 2009.

  1. idelovski macrumors regular

    Joined:
    Sep 11, 2008
    #1
    My application can use usb to serial converter to print on printers that have only the serial port. It worked well on Tiger, but on Leopard I have several issues. I use two different converters: Keyspan and some generic converter - "Prolific based device" you can find in every other computer shop. For the second one I use drivers I found on serialio.com for both ppc & intel.

    On Leopard, both converters are taken by the system and reserved for use for modem communication. Call to open() function fails. I can solve this for the second adapter by going to System preferences -> Network and manually removing the converter from the list.

    I can not make the Keyspan adapter to work on Leopard - open() fails whatever I try.

    Next problem I had was that with Prolific adapter I could open the port, print and close it only once. The second time, open() and close() calls would succeed, but write() function returns -1 and errno is set to 35 and strerror(errno) returns "service temporarily unavailable."

    On Tiger it all works well with both Keyspan and this Prolific converter. I spent some time with the code and managed to make it work on Leopard, at least with Prolific but I'm not really sure exactly what I'm doing and will it stop working in Snow Leopard. So, this version of port setup worked only on Tiger:

    Code:
       struct termios theTermios;
       int            retVal, modem;
       
       retVal = tcgetattr (fd, &theTermios);
       
       if (!retVal)  {
           memset (&theTermios, 0, sizeof(struct termios));
          
          cfmakeraw (&theTermios);     
          cfsetspeed (&theTermios, B9600);
          theTermios.c_cflag |= CS8;
          
          retVal = tcsetattr(fd, TCSANOW, &theTermios);
       }
    
       return (retVal);
    
    This code works on Leopard so second time I use the port write() does not return -1 and all prints well:
    Code:
       struct termios theTermios;
       int            retVal, modem;
       
       retVal = tcgetattr (fd, &theTermios);
       
       if (!retVal)  {
           memset (&theTermios, 0, sizeof(struct termios));
          
          cfmakeraw (&theTermios);     
          
          theTermios.c_cc[VMIN] = 0;         // NEW
          theTermios.c_cc[VTIME] = 10;       // NEW
          cfsetspeed (&theTermios, B9600);
          theTermios.c_cflag = CREAD | CLOCAL;  // NEW
          theTermios.c_cflag |= CS8;
          
          retVal = tcsetattr(fd, TCSANOW, &theTermios);
       }
    
       return (retVal);
    
    I added those lines after googling for a while, but I would appreciate if anyone could help me with explanation why it works now.
    At least, does anyone know how to make it all work on Keyspan and how do I prevent Leopard from stealing these adapters and treating them as modem ports.
     
  2. newb16 macrumors regular

    Joined:
    Feb 27, 2008
    #2
     
  3. redmonlee macrumors newbie

    Joined:
    Sep 3, 2009
    #3
  4. Andy88R macrumors newbie

    Joined:
    Sep 14, 2009
    Location:
    Germany
    #4
    Hi Igor,

    at the moment I am also writing programs to access the serial port and I am using ProlificUSB-to-Serial adapters.


    1)
    Do you open the serial port with non-blocking or blocking option?
    Here an example for opening with non-blocking operation:
    fileDescriptor = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK);

    2)
    Which port name do you use?
    If you connect the USB-to-Serial adapter to the Mac then there will be typically added the following two devices
    /dev/tty.usbserial
    /dev/cu.usbserial
    Do you use the /dev/tty.usbserial or the /dev/cu.usbserial ?

    This is an information I found about the difference between cu* and tty*:
    "The idea is to supplement software in sharing a line between incoming
    and outgoing calls. The callin device (typically /dev/tty*) is used
    for incoming traffic. Any process trying to open it blocks within the
    open() call as long as DCD is not asserted by hardware (i.e. as long
    as the modem doesn't have a carrier). During this, the callout device
    (typically /dev/cu* -- cu stands for "calling unit") can be freely
    used. Opening /dev/cu* doesn't require DCD to be asserted and
    succeeds immediately. Once succeeded, the blocked open() on the
    callin device will be suspended, and cannot even complete when DCD is
    raised, until the cu device is closed again.
    That way, you can have a getty listening on /dev/tty*, and can still
    use /dev/cu* without restrictions."

    3)
    Regarding the CLOCAL:
    If you enable the CLOCAL then the modem control lines will be ignored, that means the modem control lines DCD (Data Carrier Detect), DSR and CTS do not need a specific assertion of that line in hardware to enable the output of data on the Tx line.

    My observation is: the standard configuration after you insert the Prolific adapter is CLOCAL disabled.
    I also faced a problem for my application with Mac OSX 10.5 and 10.6 if I do not enable CLOCAL. For Linux systems I observed that the CLOCAL was enabled by default when attaching the Profilic adapter, so I did not run into this problem on that platform.

    4)
    Do you use or need any of the control lines like RTS, DTR (outputs) or CTS, DCD, DSR (inputs)?

    --
    In my application I currently face the problem:
    once issued a close() on the serial port and then open() the serial port again the first messages is frequently lost and not transmitted even if the write() call does not return any error. This problem occurs only on MacOS, the same Prolific adapter is working fine when running for example under Sidux, Xandros or SuSE Linux with the same application software. Those platforms of course use different profilic drivers for the kernel as compared to the Mac.
    Unfortunately I have neither a keyspan adapter nor an adapter using the FTDI chip to test the behaviour on that hardware.
     
  5. idelovski thread starter macrumors regular

    Joined:
    Sep 11, 2008
    #5
    I have it like this: open (deviceName, O_RDWR | O_NONBLOCK); but looking
    at the remarked code I even had it with O_WRONLY at some point.

    Well, when I wrote this post I had tty port, but I switched to cu (thanks
    to a tip by Guiyon and it all started working well in my case, but I didn't
    have time to finish everything about this.

    You see, I have this software that has a pos (point of sale) module and it
    was used on windows and classic Mac OS 9. At some point I made it work
    on OS X (Tiger), but no one bothered to use it. This summer I had few
    requests, and when I connected some epson pos printer I have in my office
    to my MacBook on Leopard nothing seemed to work any more. Well, I made
    it behave by switching to /dev/cu.usbserial but they opened the shop next day
    and I couldn't continue experimenting there, and I had to give my Keyspan
    adapter and my POS printer to some friend (to use it on old iMac on OS 9)
    for a few days and it's still in his store until today. Soon, he's gonna buy his
    own printer and return mine to me. So, now I can't try anything but I think
    switching to callout port solved all of my problems.

    Well, in my case it seems that I don't really need CTS or similar so maybe
    that helped me with the second call to open(). The only book I have that
    deals with termios is Beginning Linux Programming (Matthew, Stones) and
    since they only describe classic terminal communication, not using the port
    to print something, I'm not really quite comfortable with all this serial stuff.

    Is your application Carbon or Cocoa, or even maybe just a terminal appli-
    cation. I have Carbon application and I remember that nothing would print
    even after close() even though write() never returned any error code.

    I solved this by using event handling calls, let's call it "pumping messages"
    or calling my "event loop". That was on Tiger. I never tried how this event
    thing behaves on Leopard I think if you're having a terminal application and
    call printf() and getchar() then events are handled for you at some level.

    I think I'll get my pos printer back in a week or two and then I'll be able to
    test it some more.
     
  6. Andy88R macrumors newbie

    Joined:
    Sep 14, 2009
    Location:
    Germany
    #6
    The application is a C++ code based on Qt 4.5 libraries to provide a GUI which can be used on different platforms and because it should run under Mac OS 10.3, 10.4 and 10.5, 10.6 the Qt libraries based on Carbon are used (see http://qt.nokia.com/downloads/mac-os-cpp).
     
  7. idelovski thread starter macrumors regular

    Joined:
    Sep 11, 2008
    #7
    Well I hope you did play with options you pass to tcsetattr(), so just for fun try calling this function after tcsetattr() and after every write() and after close().

    Code:
    void  ClearOneEvent(void)
    {
       EventRecord  evtRec;
    
       WaitNextEvent (everyEvent, &evtRec, 0L, NULL);
    }
    You can't leave it like this in the real application you give to other people, just this time to test if something similar would solve your problem with the serial port.
     
  8. Andy88R macrumors newbie

    Joined:
    Sep 14, 2009
    Location:
    Germany
    #8
    Last night I did a lot of tests.

    A) Events
    I have added a function ClearOneEvent to the Carbon-Qt-based application as you have proposed and this function is called after open, close, read and write.
    Still I could see the same problems.

    B) Console applicaiton
    I have extracted the parts for the communication with the serial port from the application and put it into one file for a simple console application which can be build with a simple command line GCC compiler invocation (no Xcode is needed). This console application has no GUI and does not use Qt Library and does not use Carbon library.
    Also with this console application the problem is visible.

    C) Testing with MacOS terminal
    It came to my mind to perform a test where no self-made application is involved. So I used two MacOS terminals (bash command shell).

    Setup:
    Mac, Profilic USB-to-Serial adapter, at the serial interface of the adapter
    there is 9pin SUB-D plug with a loopback (Pin 2 TxD -> Pin 3 RxD)
    1. open two terminals (Application/Utilites/Terminal)
    2. connect the USB-to-Serial adapter to the Mac
    3. in the first terminal enter: cat /dev/cu.usbserial this will open the port and listen for incoming messages
    4. in the second terminal enter: echo "Test Message" > /dev/cu.usbserial the message will be displayed in the first terminal as expected
    5. now press Control+C in the first terminal: this will close the port
    6. now enter in the first terminal again: cat /dev/cu.usbserial this will open the port again
    7. in the second terminal type again: echo "Test Message" > /dev/cu.usbserial most time time this message gets lost and will not be displayed in the first terminal

    Repeat steps 5) 6) 7)

    If you disconnect the USB-to-Serial adapter and re-connect it to the Mac and you perform the steps starting at step 3 then agian the first time the port is opened and the message is sent, the message will be correctly received. After the close and re-open and sending a message the message is very likely lost.

    If you send two messages (execute two times echo "Test Message" > /dev/cu.usbserial in the second terminal) before you issue the close then it seems to be that after the re-open the first message is not completely lost but often the first character gets lost.
     
  9. Andy88R macrumors newbie

    Joined:
    Sep 14, 2009
    Location:
    Germany
    #9
    Now I have a USB-to-Serial adapter with a FTDI chip and both the application with the GUI and the console application are working as expected. No problems with lost messages. I am using the FTDI MacOS X driver version 2.2.9 (see http://www.ftdichip.com/Drivers/VCP.htm).

    The same application using a USB-to-Serial adapter with a Prolific chip and a the Profilic MacOS X driver version 1.2.1 (see http://www.prolific.com.tw/eng/downloads.asp?ID=31) shows the problem that after the sequence open(), write(), close(), open() and then write() the message for this write() will not be sent.
     
  10. idelovski thread starter macrumors regular

    Joined:
    Sep 11, 2008
    #10
    Thanks for the info,

    but I don't think I ever saw FTDI adapters where I buy things.

    Keyspan was Mac oriented for a very long time, so I would guess that their adapters might work OK as well.
     
  11. Andy88R macrumors newbie

    Joined:
    Sep 14, 2009
    Location:
    Germany
    #11
    Adapters with FTDI chip
    Digitus http://www.digitus.info is selling the DA-70146-1 with a FTDI FT232RL chip.
    CableMAX http://www.cablemax.com/usb-serial.cfm is also selling adapters with FTDI chips.

    Using open source driver for adapters with Prolific chip
    I removed the original Prolific driver from my MacOS system:
    kextunload ProlificUsbSerial.kext
    rm -r /System/Library/ProlificUsbSerial.kext

    (the kextunload is only necessary if the driver is currently loaded)

    Then I installed the open source driver for the Prolific PL2303 chips (you can download this driver from the internet: http://sourceforge.net/projects/osx.../osx-pl2303-0.3.1-10.4-universal.dmg/download )

    The device which will be created is /dev/cu.PL2303-xxxxxxxx where xxxxxxxx is depending on the USB port where the adapter is connected.

    With this driver there were no problems even if using several open() -> write() -> sleep() -> read() -> close() cycles.

    Meanwhile I have a test program which is doing those cycles automatically for a given number of times and is showing if there was encountered a problem (sent message could not be received back when using a hardware loopback) or if the complete number of test runs where successfully completed.
     
  12. idelovski thread starter macrumors regular

    Joined:
    Sep 11, 2008
    #12
    Thanks for all the additional info. Just found this somewhat related thread on cboard. Hope you'll find something interesting.
     

Share This Page