Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

idelovski

macrumors regular
Original poster
Sep 11, 2008
235
0
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.
 

newb16

macrumors regular
Feb 27, 2008
100
0
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 don't know a thing about both these converters, but google says that Keyspan _doesn't_ have issues with leopard with some driver version.
 

Andy88R

macrumors newbie
Sep 14, 2009
5
0
Germany
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.
 

idelovski

macrumors regular
Original poster
Sep 11, 2008
235
0
Hi Igor,

at the moment I am also writing programs to access the serial port and I am using Profilic USB-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);

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.

2)
Do you use the /dev/tty.usbserial or the /dev/cu.usbserial ?

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.

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.

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.

My observation is: the standard configuration after you insert the Profilic 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 Profilic 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.

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.
 

idelovski

macrumors regular
Original poster
Sep 11, 2008
235
0
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.

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.
 

Andy88R

macrumors newbie
Sep 14, 2009
5
0
Germany
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.
 

Andy88R

macrumors newbie
Sep 14, 2009
5
0
Germany
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.
 

idelovski

macrumors regular
Original poster
Sep 11, 2008
235
0
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.
 

Andy88R

macrumors newbie
Sep 14, 2009
5
0
Germany
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.