views:

350

answers:

3

Hi,

I need to develop an interface between a Laboratory Information System (LIS), developed in .NET, and the Remisol 2000 Data Manager , which is a API for lab instrumentation systems made by Beckman Coulter Inc. The idea is to fetch the test results programatically into the LIS.

Are there any resources on the web that can give me a start ? I presume i need to open a Socket , but the documentation only mentions the message structures for the Protocols like Synchron LX20, Synchron CX7, ASTM, ASTMH2 and LIS Gen.S.

All of them use the Serial protocol.

Thanks, Chak.

using System; using System.IO.Ports; using System.Threading;

public class ClientToBeckmanDL2000 { static bool _continue; static SerialPort _serialPort; static bool keepRetrying = true;

public static void Main()
{

    CreateNewSerialPortAndOpenIt();

    SendAndReceiveMessagesInALoop();

    CloseTheSerialPort();
}

private static void CloseTheSerialPort()
{
    _serialPort.Close();
}

private static void SendAndReceiveMessagesInALoop()
{
    StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
    string outputMessage, inputMessage;
    _continue = true;
    DateTime startTime, endTime;
    TimeSpan diffInSeconds;
    int retryCounter = 0;


    Console.WriteLine("Type QUIT to exit");

    try
    {
        while (_continue)
        {
            outputMessage = Console.ReadLine();

            _serialPort.WriteLine(
                    String.Format("{0}", outputMessage));

            if (outputMessage.Equals("ENQ") || outputMessage.Equals("<ENQ>") || outputMessage.Equals("EOT SOH") || outputMessage.Equals("<EOT> <SOH>") || outputMessage.Equals("<EOT><SOH>"))
            {
                while (keepRetrying.Equals(true))
                {
                    startTime = DateTime.Now;
                    inputMessage = string.Empty;

                    inputMessage = GetResponseFromServerInALoop();



                    endTime = DateTime.Now;
                    diffInSeconds = endTime - startTime;

                    // if the time for response crosses 15 seconds keep retrying
                    if (diffInSeconds.Seconds > 15)
                    {
                        retryCounter++;
                        keepRetrying = true;
                        Console.WriteLine("Retrying..." + retryCounter.ToString());
                        Console.WriteLine(" ");
                        if (retryCounter > 7)
                        {
                            keepRetrying = false;
                            Console.WriteLine("Tried more than 7 times . Line down. Please try again later...");
                            break;
                        }


                    }
                    else
                        if (inputMessage.ToString().Length > 0 && (inputMessage.Equals("STX")))
                        {
                            Console.WriteLine("Response is " + inputMessage.ToString() + " The Remisol server is bidding for line. Try to send your message later ... ");
                            keepRetrying = false;
                        }
                        else
                            if (inputMessage.ToString().Length > 0 && (!inputMessage.Equals("ACK") && !inputMessage.Equals("NAK") && !inputMessage.Equals("STX")))
                            {
                                Console.WriteLine("Response is " + inputMessage.ToString() + " It should be ACK or NAK or STX. Try again ... ");
                                keepRetrying = false;
                            }
                            else
                                if (inputMessage.ToString().Length > 0 && (inputMessage.Equals("NAK")))
                                {
                                    Console.WriteLine("Response is " + inputMessage.ToString() + " It should be ACK. Try again ... ");
                                    keepRetrying = false;
                                }
                                else
                                {
                                    Console.WriteLine("Please key in [00,800,01]97<CR><LF> to check Remisol..");
                                    keepRetrying = false;
                                }
                    if (keepRetrying.Equals(true))
                    {
                        _serialPort.WriteLine(String.Format("{0}", outputMessage));
                    }
                }
            }
            else
                if (outputMessage.Equals("[00,800,01]97<CR><LF>"))
                {
                    do
                    {
                        inputMessage = _serialPort.ReadLine();
                        System.Threading.Thread.Sleep(1000);
                        keepRetrying = false;
                        Console.WriteLine(inputMessage);

                    } while (inputMessage.Equals(null));

                    Console.WriteLine("Response is " + inputMessage.ToString());
                }
            if (stringComparer.Equals("quit", outputMessage))
            {
                _continue = false;
            }

        }
    }
    catch (Exception) { }
}

private static string GetResponseFromServerInALoop()
{
    string inputMessage = string.Empty;


    do {
        inputMessage = _serialPort.ReadLine();

        System.Threading.Thread.Sleep(10);
        keepRetrying = false;
        Console.WriteLine(inputMessage);

    }
    while (inputMessage.Equals(string.Empty));

    return inputMessage;
}

private static void CreateNewSerialPortAndOpenIt()
{
    _serialPort = new SerialPort();

    // Allow the user to set the appropriate properties.
    _serialPort.PortName = SetPortName(_serialPort.PortName);
    _serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
    _serialPort.Parity = SetPortParity(_serialPort.Parity);
    _serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
    _serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
    _serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);

    // Set the read/write timeouts
    //_serialPort.ReadTimeout = 0; -- this is being commented since this testing program needs to run for long time without timeouts. The default is anyway 0 which is infinite timeouts
    //_serialPort.WriteTimeout = 500000; -- this too is being commented out since it needs to run infinitely for test

    _serialPort.Open();
}


public static string SetPortName(string defaultPortName)
{
    string portName;

    Console.WriteLine("Available Ports:");
    foreach (string s in SerialPort.GetPortNames())
    {
        Console.WriteLine("   {0}", s);
    }

    Console.Write("COM port({0}): ", defaultPortName);
    portName = Console.ReadLine();

    if (portName == "")
    {
        portName = defaultPortName;
    }
    return portName;
}

public static int SetPortBaudRate(int defaultPortBaudRate)
{
    string baudRate;

    Console.Write("Baud Rate({0}): ", defaultPortBaudRate);
    baudRate = Console.ReadLine();

    if (baudRate == "")
    {
        baudRate = defaultPortBaudRate.ToString();
    }

    return int.Parse(baudRate);
}

public static Parity SetPortParity(Parity defaultPortParity)
{
    string parity;

    Console.WriteLine("Available Parity options:");
    foreach (string s in Enum.GetNames(typeof(Parity)))
    {
        Console.WriteLine("   {0}", s);
    }

    Console.Write("Parity({0}):", defaultPortParity.ToString());
    parity = Console.ReadLine();

    if (parity == "")
    {
        parity = defaultPortParity.ToString();
    }

    return (Parity)Enum.Parse(typeof(Parity), parity);
}

public static int SetPortDataBits(int defaultPortDataBits)
{
    string dataBits;

    Console.Write("Data Bits({0}): ", defaultPortDataBits);
    dataBits = Console.ReadLine();

    if (dataBits == "")
    {
        dataBits = defaultPortDataBits.ToString();
    }

    return int.Parse(dataBits);
}

public static StopBits SetPortStopBits(StopBits defaultPortStopBits)
{
    string stopBits;

    Console.WriteLine("Available Stop Bits options:");
    foreach (string s in Enum.GetNames(typeof(StopBits)))
    {
        Console.WriteLine("   {0}", s);
    }

    Console.Write("Stop Bits({0}):", defaultPortStopBits.ToString());
    stopBits = Console.ReadLine();

    if (stopBits == "")
    {
        stopBits = defaultPortStopBits.ToString();
    }

    return (StopBits)Enum.Parse(typeof(StopBits), stopBits);
}

public static Handshake SetPortHandshake(Handshake defaultPortHandshake)
{
    string handshake;

    Console.WriteLine("Available Handshake options:");
    foreach (string s in Enum.GetNames(typeof(Handshake)))
    {
        Console.WriteLine("   {0}", s);
    }

    Console.Write("Stop Bits({0}):", defaultPortHandshake.ToString());
    handshake = Console.ReadLine();

    if (handshake == "")
    {
        handshake = defaultPortHandshake.ToString();
    }

    return (Handshake)Enum.Parse(typeof(Handshake), handshake);
}

}

+1  A: 

I've done similar interfacing for a LIMS system to lab instruments (in my case, thermocyclers).

I don't know about the specific instruments you mentioned, but many lab instruments use a serial interface of some form. The physical layer could be either rs232 (if the instrument is intended to exist standalone on a bench) or it could be rs485 (if there are multiple instruments that need to be ganged together in a "daisy-chain" configuration). The protocol level can be a pretty wide variety of simple message/response patterns. Some of these are actually standards (ASTM 1394), others are "home-made" jobs that consist of simple blocks of bytes with op-codes, data and a checksum. Whatever it is, you'll need good documentation if you don't have API libraries you can use. You might have to make phone calls to get this stuff, it isn't always available on the internet.

One of the problems that you'll have is that servers that run LIMS systems are often in a datacenter somewhere and your instruments are in a lab. To make it worse, the servers don't have serial ports, and the instruments don't have ethernet.

To get around this, you'll want to use "serial terminal servers" or "serial device servers" (for example... link). These are little metal boxes that take ethernet traffic and route it to one or more serial ports (the ports can be configured as rs232 or rs422 or rs485). On the server, you install a driver that makes these ports on the remote terminal server appear as an actual ports to the server application. Alternatively, you can also choose to route data to/from a specific TCP/IP socket to a specific serial port.

If you get it to work, it is a pretty neat rewarding project that saves a lot of time. Good luck!

Angelo
I have added the code of my client program to my question now. I am using a rs232 cable connecting client and server. The same client program works with a 'dummy' server program made to act like an ASTMH server. It fails when i plug it into the Remissol server PC and send the EOT SOH or ENQ messages.
Chakra
You do realize that "ACK" and "STX" are actually ascii characters and not three letter strings, right?
Angelo
Ok so instead of sending a string like ENQ and waiting for a string like ACK, i need to send ASCII of ENQ and expect ASCII of ACK ?
Chakra
Yes, that's right. These are known as ascii control characters. Their values are defined in any ascii table (for example, search ASCII in wikipedia). Usually, these characters are written with angle-brackets to indicate that they are to be replaced with the ascii content. eg <ACK> means the ascii char with the value 0x06 in hex.
Angelo
A: 

Hello,

I am just wondering if you are still developing the application. If so, I'd like to show you an application that I primarily developed for communicating clinical devices to fetch the test results but it can be used in any case to make serial communication easier between a host computer and a device running on a serial port. You don't have to know anything about what's going on serial data communication and what special ascii characters (e.g., ENQ, ACK) mean. All you need to do is to write codes as if you develop regular application and compile into a binary file.

Please take a look at the project website and feel free to contact with any questions.

Project website

Best regards,

Orhan

albay
A: 

Hello I am also developing an application in C# to Interface vitros 250 and vitros eciq.if you can help me please share your email. sobin sobinj at gmail.com

sobin