Recently I was working on a php command line program that required access to a serial port.
Initially developed under Linux the program was then shifted to it’s permanent location on a FreeBSD server. This is where we first started having problems. Initially we discovered the server didn’t have a native serial port. We fixed this using a USB to serial converter/dongle (FTDI Chipset). This was fine as FreeBSD has the ufdti kernel module. Upon loading the module new devices appears in /dev
crw-rw---- 1 uucp dialer 0, 157 Oct 6 08:39 /dev/cuaU0 crw-rw---- 1 uucp dialer 0, 158 Oct 6 08:39 /dev/cuaU0.init crw-rw---- 1 uucp dialer 0, 159 Oct 6 08:39 /dev/cuaU0.lock crw-rw-rw- 1 root wheel 0, 154 Jan 8 10:50 /dev/ttyU0 crw------- 1 root wheel 0, 155 Oct 6 08:39 /dev/ttyU0.init crw------- 1 root wheel 0, 156 Oct 6 08:39 /dev/ttyU0.lock
We attempted to connect to our device using screen (screen /dev/ttyU0 115200) and everything worked as expected. We could send AT commands to the device all ok.
We then stopped screen and ran our php program. It ended up hanging on a fgets call to the serial port. This is really strange we though.
Next we queried the port to find out what baud rate it was set at:
>stty -f /dev/ttyu0 speed 9600 baud; lflags: echoe echoke echoctl oflags: tab0 cflags: cs8 -parenb
Strange we thought as we’d just connected with screen at 115200. Under linux we use screen to set the baud rate, all other programs accessing the port use the port at 115200. So what had set it back to 9600 baud?
We tried to use stty to set the speed:
>stty -f /dev/ttyU0 speed 115200
>stty -f /dev/ttyu0 speed 9600 baud; lflags: echoe echoke echoctl oflags: tab0 cflags: cs8 -parenb
What on earth was happening? We set the speed to 115200 but directly quering the port again indicated it was still at 9600 baud? At this point we were perplexed.
Eventually we found the solution. The newer FreeBSD terminal drivers provide the *.init devices, in this case /dev/ttyU0.init . These devices indicate the terminal settings to be applied to the terminal when the device is closed. Whilst Linux leaves the device in the same state the last program put the port into, FreeBSD restores the terminals state to what ever is specified in the init file. So a quick command:
> stty -f /dev/ttyU0.init -icanon -isig -echo echoe echok echoke echoctl -icrnl -ixany -imaxbel ignpar -opost -onlcr -oxtabs cs8 -parenb -hupcl clocal
And then to check:
> stty -f /dev/ttyU0 speed 115200 baud; lflags: -icanon -isig -echo echoe echok echoke echoctl iflags: -icrnl -ixany -imaxbel ignpar oflags: -opost -onlcr -oxtabs cflags: cs8 -parenb -hupcl clocal
Excellent. The terminal was now configured exactly how we wanted. We ran the program and it worked like a charm!