Tuesday, November 8, 2011

Linux simple serial console

I am trying to refit an Intel SS4200 NAS unit that came as a Scaleo Home Server 2205 as a linux server. After browsing the internet for what seems like a whole week, looking up ways to install a simple Linux system on a headless server, using the serial console for text-IO instead of a monitor and a keyboard, I finally managed to do so. The SS4200 unit uses 115200 baud configuration for the serial port and you need a null-modem cable to connect it to your PC, but also you need to order a IDC10 to DB9 connector, or possibly just through something together with wire connected to a serial cable. For more explanation, see this blog.

I used a simple Debian netinst ISO (torrent here) and put it on a USB stick made bootable with unetbootin. For serial communication, I use PuTTy. When you have created your USB stick with the debian netinst image, modify the syslinux.cfg file on it to contain just the following:

default linux
prompt 1
display boot.msg
timeout 100
label linux
  kernel vmlinuz
  append $INITRDARG root=$rootdev

Save and close, plug the stick into your SS4200. Connect your PCs serial port to the SS4200 using a nullmodem adapter. Open up PuTTy and set it to connect to your serial port, using 115200 baud. Make sure you know your serial adapters name (most commonly COM1 on Windows, ttyS0 on linux, though be careful when using a USB to serial adapter and check in the device manager on windows, or ls tty* on linux so you have the correct name).

When PuTTy is set up and you power on your SS4200, you should get some text. Immediately hit DEL repeatedly in PuTTy after powering on the unit to get into the BIOS. There you have to alter the boot order to enable booting from the USB stick. Do that, save and exit BIOS. Then when it restarts, it should go to the GRUB screen with a single option. Hit Enter or wait for the timeout to expire, and you should find yourself in the debian expert installation menu.

Good Luck from there!

Monday, October 18, 2010

I wanted to read out a Lakeshore 218 Temperature monitor through a serial connection, but Lakeshore does not supply a program to extract any data, so I have to write my own... Here is how I stumbled in setting up a connection to the monitor:

First I have to connect a serial to USB adapter and find a driver for it for Linux. Luckily, the one I bought (Radioshack brand) uses a Prolific chipset for which there are preinstalled drivers available, so it worked plug and play (which I figured out only after plugging it into a terminal software and sending some messages back and forth with another PC). I also had to use the device name /dev/ttyUSB0 and not /dev/usb/ttyUSB0 as was suggested in some other articles on the net.

I am using Code::Blocks IDE 8.02 for Ubuntu on KDE to write a program that will determine how much data there is on the monitor, and then query each dataset, while writing all the data into a .csv file.

I am writing this in plain C, as this seems to be the most straightforward way of getting the data. It is recommended in several places to use threaded querying, separate threads for sending and reading and other stuff, but I am just trying to get something to work before I delve into some more exotic stuff that I will have to debug.

I dug through a few tutorials that were relatively unsuccessful, and finally stumbled upon a wikibook explaining the termios.h header file that was referenced in some other tutorials. It had this convenient piece of code (that originally asked you to supply an argument when opening the program to specify the serial device to open, but I modified it to statically open my USB to serial adapter (/dev/ttyUSB0)).



#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
 
int main(int argc,char** argv)
{
        struct termios tio;
        struct termios stdio;
        int tty_fd;
        fd_set rdset;
 
        unsigned char c='D';
 
//        printf("Please start with %s /dev/ttyS1 (for example)\n",argv[0]);
        memset(&stdio,0,sizeof(stdio));
        stdio.c_iflag=0;
        stdio.c_oflag=0;
        stdio.c_cflag=0;
        stdio.c_lflag=0;
        stdio.c_cc[VMIN]=1;
        stdio.c_cc[VTIME]=0;
        tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
        tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
        fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);       // make the reads non-blocking
 
 
 
 
        memset(&tio,0,sizeof(tio));
        tio.c_iflag=0;
        tio.c_oflag=0;
        tio.c_cflag=CS8|CREAD|CLOCAL;           // 8n1, see termios.h for more information
        tio.c_lflag=0;
        tio.c_cc[VMIN]=1;
        tio.c_cc[VTIME]=5;
 
        tty_fd=open(argv[1], O_RDWR | O_NONBLOCK);      
        cfsetospeed(&tio,B115200);            // 115200 baud
        cfsetispeed(&tio,B115200);            // 115200 baud
 
        tcsetattr(tty_fd,TCSANOW,&tio);
        while (c!='q')
        {
                if (read(tty_fd,&c,1)>0)        write(STDOUT_FILENO,&c,1);              // if new data is available on the serial port, print it out
                if (read(STDIN_FILENO,&c,1)>0)  write(tty_fd,&c,1);                     // if new data is available on the console, send it to the serial port
        }
 
        close(tty_fd);
}