Search code examples
c#serial-portbarcode-scanner

C# Serial Port communication issue


I have a problem with a small C# application. The application has to connect through a serial port to a bar code scanner which reads a Data Matrix code. The Data Matrix code represents an array of bytes which is a zip archive. I read a lot about the way SerialPort.DataReceived work but I can't find an elegant solution to my problem. And the application should work with different bar code scanners so i can't make it scanner specific. Here is some of my code:

    using System;
    using System.IO;
    using System.IO.Ports;
    using System.Windows.Forms;
    using Ionic.Zip;

    namespace SIUI_PE
    {
        public partial class Form1 : Form
        {
            SerialPort _serialPort;

        public Form1()
        {

            InitializeComponent();


        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                _serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error:" + ex.ToString());
                return;
            }
            _serialPort.Handshake = Handshake.None;
            _serialPort.ReadBufferSize = 10000;
            _serialPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
            _serialPort.Open();

        }
        void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
           byte[] data = new byte[10000];
           _serialPort.Read(data, 0, 10000);
           File.WriteAllBytes(Directory.GetCurrentDirectory() + "/temp/fis.zip", data);
             try
             {
                 using (ZipFile zip = ZipFile.Read(Directory.GetCurrentDirectory() + "/temp/fis.zip"))
                 {
                     foreach (ZipEntry ZE in zip)
                     {
                         ZE.Extract(Directory.GetCurrentDirectory() + "/temp");
                     }
                 }
                 File.Delete(Directory.GetCurrentDirectory() + "/temp/fis.zip");

             }
             catch (Exception ex1)
             {
                 MessageBox.Show("Corrupt Archive: " + ex1.ToString());

             }
        }

    }
}

So my question is: How can I know that I read all the bytes the scanner sent?


Solution

  • The code I've got for reading barcode data, which has been working flawlessly in production for several years looks like this:

    Note, my app has to read standard UPC barcodes as well as GS1 DataBar, so there's a bit of code you may not need...

    The key line in this is:

    string ScanData = ScannerPort.ReadExisting(); 
    

    which is found in the DoScan section, and simply reads the scan data as a string. It bypasses the need to know how many bytes are sent, and makes the rest of the code easier to deal with.


         // This snippet is in the Form_Load event, and it initializes teh scanner
            InitializeScanner();
            ScannerPort.ReadExisting();
            System.Threading.Thread.Sleep(1000);
         // ens snippet from Form_Load.
    
            this.ScannerPort.DataReceived += new SerialDataReceivedEventHandler(ScannerPort_DataReceived);
    
    
    delegate void DoScanCallback();  // used for updating the form UI
    
    void DoScan()
        {
            if (this.txtCouponCount.InvokeRequired)
            {
                DoScanCallback d = new DoScanCallback(DoScan);
                this.Invoke(d);
                return;
            }
            System.Threading.Thread.Sleep(100);
            string ScanData = ScannerPort.ReadExisting();
            if (isInScanMode)
            {
                try
                {
                    HandleScanData(ScanData);
                }
                catch (Exception ex)
                {
                         System.Media.SystemSounds.Beep.Play();
                         MessageBox.Show("Invalid Scan");
                }
            }
        }
        void ScannerPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            // this call to sleep allows the scanner to receive the entire scan.
            // without this sleep, we've found that we get only a partial scan.
            try
            {
                DoScan();
            }
            catch (Exception ex)
            {
                    System.Media.SystemSounds.Beep.Play();
                    MessageBox.Show("Unable to handle scan event in ScannerPort_DataReceived." + System.Environment.NewLine + ex.ToString());
            }
    
        }
        void Port_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
        {
    
              System.Media.SystemSounds.Beep.Play();
              MessageBox.Show(e.EventType.ToString());
        }
        private void HandleScanData(string ScanData)
        {
            //MessageBox.Show(ScanData + System.Environment.NewLine + ScanData.Length.ToString());
    
            //Determine which type of barcode has been scanned, and handle appropriately.
            if (ScanData.StartsWith("A") && ScanData.Length == 14)
            {
                try
                {
                    ProcessUpcCoupon(ScanData);
                }
                catch (Exception ex)
                {
                         System.Media.SystemSounds.Beep.Play();
                         MessageBox.Show("Unable to process UPC coupon data" + System.Environment.NewLine + ex.ToString());
    
                }
            }
            else if (ScanData.StartsWith("8110"))
            {
                try
                {
                    ProcessDataBarCoupon(ScanData);
                }
                catch (Exception ex)
                {
                         System.Media.SystemSounds.Beep.Play();
                         MessageBox.Show("Unable to process DataBar coupon data" + System.Environment.NewLine + ex.ToString());
                }
            }
            else
            {
                    System.Media.SystemSounds.Beep.Play();
                    MessageBox.Show("Invalid Scan" + System.Environment.NewLine + ScanData);
            }
    
    
        }
    
    
        private void InitializeScanner()
        {
            try
            {
                ScannerPort.PortName = Properties.Settings.Default.ScannerPort;
                ScannerPort.ReadBufferSize = Properties.Settings.Default.ScannerReadBufferSize;
                ScannerPort.Open();
                ScannerPort.BaudRate = Properties.Settings.Default.ScannerBaudRate;
                ScannerPort.DataBits = Properties.Settings.Default.ScannerDataBit;
                ScannerPort.StopBits = Properties.Settings.Default.ScannerStopBit;
                ScannerPort.Parity = Properties.Settings.Default.ScannerParity;
                ScannerPort.ReadTimeout = Properties.Settings.Default.ScannerReadTimeout;
                ScannerPort.DtrEnable = Properties.Settings.Default.ScannerDtrEnable;
                ScannerPort.RtsEnable = Properties.Settings.Default.ScannerRtsEnable;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to initialize scanner.  The error message received will be shown next.  You should close this program and try again.  If the problem persists, please contact support.", "Error initializing scanner");
                MessageBox.Show(ex.Message);
                Application.Exit();
            }
    
    
        }