0

I'm making a keypad project. 1st user input is a 10-digit id. Then follow with 6-digit password. I've been thinking how to assign both input into different arrays upon receiving them from the serial port. Here is my attempt so far.

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    char[] id = new char[11];
    char[] pass = new char[7];
    int length;

    try
    {
        serialPort1.ReadTimeout = 100;
        do
        {
            length = serialPort1.Read(id, 0, 11);
        } while (length > 0);
    }
    catch (TimeoutException) { MessageBox.Show(id.ToString()); }

    try
    {
        serialPort1.ReadTimeout = 100;
        do
        {
            length = serialPort1.Read(pass, 0, 7);
        } while (length > 0);
    }
    catch (TimeoutException) { MessageBox.Show(pass.ToString()); }
}

After debugging, the problem are:

  1. The MessageBox.Show() would only display empty char array.
  2. The arrays maybe did not contain anything.
  3. Using the ReadTimeout ,user need to press the keypad in a given time which is not so flexible in design.

Any help or tips are really welcomed. Thanks in advance. I don't mind to built from scratch if you suggest so.

  • When assigning your arrays, you've removed one from the size instead of adding one... They should be `char[] id = new char[11]; char[] pass = new char[6];` instead, they currently aren't big enough to hold a 10 char and 6 char string. – Serdalis Sep 09 '15 at 00:09
  • Should I go with `char[] id = new char[11]; char[] pass = new char[7];` ? 6 or 7 doesn't matter right? Correct me if I'm wrong – Nabil Fikri Sep 09 '15 at 00:13
  • You are correct, sorry I miscounted for the second array. The extra value is to hold the null terminator for the string, which you may or may not need since this is a data stream but it is good to account for. – Serdalis Sep 09 '15 at 00:14
  • I've followed your suggestion. However, after each `ReadTimeout`, the `MessageBox` still display empty char array. I'm not sure how to proceed anymore – Nabil Fikri Sep 09 '15 at 00:26
  • I wasn't trying to solve the whole question, just a tip. But that said I do have some working serial port code i'll post for you and you can attempt to manipulate it to do what you want. – Serdalis Sep 09 '15 at 00:31
  • Actually better idea, [This StackOverflow Question on Serial Reading](http://stackoverflow.com/questions/13754694/what-is-the-correct-way-to-read-a-serial-port-using-net-framework) is exactly what you need. It will show you exactly what to do to get your code working. – Serdalis Sep 09 '15 at 00:37
  • @Serdalis Thank you for the link. It finally working after referring some of it. – Nabil Fikri Sep 09 '15 at 06:04

2 Answers2

3

This is where it goes wrong

do
{
     length = serialPort1.Read(id, 0, 11);
} while (length > 0);

the code means that try to read 11 byte into id, then return the actual number of byte read. So if there are 100 bytes available, length will be 11. If there are only 5 bytes available to read, length will be 5. Because length > 0, it loops again to try to read 11 bytes again until it reads nothing. Subsequent read will override data in the previous read as you are reading data into the same array.

Same goes with

do
{
     length = serialPort1.Read(pass, 0, 7);
} while (length > 0);
Viet Nguyen
  • 406
  • 3
  • 12
3

My suggestion is to:

  • unhook event DataReceived on the first line of method serialPort1_DataReceived from serialPort1 object
  • for the id char array, reduce to size of 10 instead of 11 because you're reading 10 digits ID
  • same goes to pass char array, reduce it to 6

Suggested code:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // unhook event
    serialPort1.DataReceived -= serialPort1_DataReceived;

    char[] id = new char[10];
    char[] pass = new char[6];

    try
    {
        // send unique start bit from connected serial port device to indicate begin of transmission
        byte ack = serialPort1.ReadByte();
        while (ack != 0xC0)
        {
            ack = serialPort1.ReadByte(); // <- continuously read from serial port until start bit is found
        }

        // try to increase timeout as 100 ms is too fast
        serialPort1.ReadTimeout = 1000;
        for (int i = 0; i < 10; i++)
        {
            id[i] = (char)serialPort1.ReadByte();
        }
    }
    catch (TimeoutException) { MessageBox.Show(id.ToString()); }

    try
    {
        // send unique start bit from connected serial port device to indicate begin of transmission
        byte ack = serialPort1.ReadByte();
        while (ack != 0xC0)
        {
            ack = serialPort1.ReadByte(); // <- continuously read from serial port until start bit is found
        }

        // try to increase timeout as 100 ms is too fast
        serialPort1.ReadTimeout = 1000;
        for (int i = 0; i < 6; i++)
        {
            pass[i] = (char)serialPort1.ReadByte();
        }
    }
    catch (TimeoutException) { MessageBox.Show(pass.ToString()); }

    // rehook event
    serialPort1.DataReceived += serialPort1_DataReceived;
}
  • There's no need to unsub the event. You will not receive the next dataReceived event until you've exited the stack for the first one. – Bill Tarbell Jun 10 '22 at 14:49