0

I'm creating a program to work with some equipment using serial port. I have documentation where there're details how to send command by port. It works very well but I should get some information about status of the equipment. I tried everything but I'm not confident in these type of developing. May be I missed something.

From the documentation:

There are totally 21 commands, 20 commands are of opening, 1 command is of reading status

Open command:

Address Command fixed value( 0x55) lock number

Address 0XF2 0X55 0X01

Address 0XF2 0X55 0X02

Address 0XF2 0X55 0X03

......

Above commands execution

Success returns : Address+0X59+0X59

Failure returns: Address+0X5E+0X5E

    /// <summary>
    /// Send open lokcer door command
    /// </summary>
    /// <param name="boardAddress">0 means open left slave cabinet,1 means open right slave cabinet</param>
    /// <param name="command"></param>
    /// <returns></returns>
    public byte[] OpenBox(byte boardAddress, byte command)
    {
        var openCommand = new byte[5];
        openCommand[0] = (byte)(255 - boardAddress);
        openCommand[0] = 0xF2;
        openCommand[1] = 0x55;
        openCommand[2] = command;

        openCommand[3] = 0X00;
        openCommand[4] = 0X00;
        try
        {
            if (!serialPort.IsOpen)
            {
                //serialPort.WriteBufferSize = 5;
                serialPort.Open();
            }
            serialPort.DiscardInBuffer();
            serialPort.Write(openCommand, 0, 3);
            return openCommand;
        }
        catch (ArgumentException ex)
        {
            throw new InvalidOperationException("Locker cell can not be opened.", ex);
        }
    }

It works very well but last 2 bytes return nothing. They are always 0X00. Also I'm using SerialPortDataReceived but I always get 0 there.

 public void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        DBException.WriteLog("");
        DBException.WriteLog("Serial port data received");
        var sp = (SerialPort)sender;
        DBException.WriteLog("Read existing = " + sp.ReadExisting());
        try
        {
            DBException.WriteLog("Length = " + sp.BytesToRead);
            if (serialPort.BytesToRead == 4)
            {
                var readBuffer = new byte[4];
                sp.Read(readBuffer, 0, serialPort.BytesToRead);

                DBException.WriteLog("Read serial port :" + readBuffer.ByteArrayToString());

                //                    RaiseLockerStatusEvent(readBuffer.ByteArrayToString());
            }
        }
        catch (Exception ex)
        {
            DBException.WriteLog(ex);
        }
    }

QUESTION 1 How to get Success or Failure returns? I think they should be in the last 2 bytes.

QUESTION 2 How to get all states? I get nothing at the present.

Documentation:

Read lock status command: Address + Data1 + Data2 + Data3 Address: 0XF10X55 Data1 Data2 Data3 0000 lock20 … lock17 lock16 … lock9 lock8 … lock1 The first 4 digits is fixed number of 0000 Sample: 0000 0000 0000 0001 0000 0001 means lock1 and lock9 is open, others are closed Note: for some type of electronic lock, “1” means close, “0” means open.

My snippet

/// <summary>
    /// Send check machine(cabinet) status command
    /// </summary>
    /// <param name="address">0 means check left cabinet, 1 means check right cabinet </param>
    /// <returns></returns>
    public byte[] SendCheckLockControlStatueCommand(byte address)
    {
        lock (this)
        {
            var checkCommand = new byte[6];
            checkCommand[0] = Convert.ToByte(255 - address);
            checkCommand[1] = 0xF1;
            checkCommand[2] = 0x55;

            checkCommand[3] = 0x00;
            checkCommand[4] = 0x00;
            checkCommand[5] = 0x00;
            try
            {
                if (!serialPort.IsOpen)
                {
                    //                    serialPort.WriteBufferSize = 5;
                    serialPort.Open();
                }

                //Send inquiry command
                serialPort.DiscardInBuffer();
                //                    serialPort.DiscardOutBuffer();
                serialPort.Write(checkCommand, 0, 6);

                return checkCommand;
            }
            catch (ArgumentException ex)
            {
                throw new InvalidOperationException("Locker cell can not be opened.", ex);
            }
        }
    }
Dmitrii Polianskii
  • 565
  • 1
  • 8
  • 21

1 Answers1

1

Never ever use the asynchronous DataReceived event the way you do! You need to decide: Either you want to communicate synchronously or asynchronously. If you want the latter, never call or even wait in DataReceived.

Instead, put the stuff you receive into a buffer and handle it as soon as a message is complete.

Also, the call to ReadExisting already reads everything from the serial port that is there so that Read is highly probably to block!

It should rather look something like this:

List<byte> receivedBinaryData = new List<byte>();

public void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var sp = (SerialPort)sender;
    string availableData = sp.ReadExisting();
    byte[] inputAsASCII = Encoding.ASCII.GetBytes(availableData);

    DBException.WriteLog("");
    DBException.WriteLog("Serial port data received");
    DBException.WriteLog("Read existing = " + availableData);
    try
    {
        // Add the bytes to the receivedBinaryData List
        receivedBinaryData.AddRange(inputAsASCII);

        // If the message length is reached or exceeded, do something
        if (receivedBinaryData.Length >= 4)
           ....
    }
    catch (Exception ex)
    {
        DBException.WriteLog(ex);
    }
}
Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139
  • Thank you very much. I guess I'm getting into it. But actually I prefer to communicate synchronously. And I think I should Wait for some time in my SendingCommand method and then Read data. Could you explain it please? I'll be appreciate. – Dmitrii Polianskii Mar 02 '16 at 05:51
  • I think I have found the right answer to read data from serial port. It'm gonna use AutoResetEvent all details are here. http://stackoverflow.com/questions/11782053/serialport-wait-for-response Thanks again. – Dmitrii Polianskii Mar 02 '16 at 06:03
  • If you want to communicate synchronously, you might want to call `Read` after you `Write` until you have your answer. Please note that this might block your application forever if there is no answer. Using a WaitHandle with a timeout may indeed be the best solution. – Thorsten Dittmar Mar 02 '16 at 06:30