카테고리 없음

C# 윈폼) 허니웰 바코드 스캐너 프로그램

joo_coding 2025. 11. 12. 18:27

Honeywell.sln
0.00MB

 

 

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports; // 시리얼 통신
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

/*
 * 데이터를 읽어요
 * 식별자에 맞게 파싱해요
 * 객체에 넣어요 (Vo객체로 매핑)
 * ui 바인딩해요
 * db 업데이트해요
 */

namespace Honeywell
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            comboBox1.DataSource = SerialPort.GetPortNames(); // 시리얼 포트 목록 불러오기
            comboBox1.SelectedIndex = 0; // 기본값=첫번째꺼

        }

        public Vo UiVer = new Vo(); // ui 바인딩용 객체 인스턴스
        public Vo DbVer = new Vo(); // db 업데이트용 객체 인스턴스

        // [ 연결부 ] /////////////////////////////////////////////////////////////////////
        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(comboBox1.Text))
            {
                MessageBox.Show("포트를 선택하세요.");
                return;
            }

            try
            {
                if (!serialPort1.IsOpen)
                {
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.BaudRate = 115200;
                    serialPort1.DataBits = 8;
                    serialPort1.StopBits = StopBits.One;
                    serialPort1.Parity = Parity.None;

                    serialPort1.DataReceived += serialPort1_DataReceived;
                    serialPort1.Open();

                    comboBox1.Enabled = false; // 버튼 비활성화
                    MessageBox.Show("스캐너 연결 성공!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("연결 실패: " + ex.Message);
            } 

        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            {
                if (serialPort1.IsOpen)  //시리얼포트가 열려 있으면
                {
                    serialPort1.Close();  //시리얼포트 닫기

                    label_status.Text = "포트가 닫혔습니다.";
                    comboBox1.Enabled = true;  //COM포트설정 콤보박스 활성화
                }
                else  //시리얼포트가 닫혀 있으면
                {
                    label_status.Text = "포트가 이미 닫혀 있습니다.";
                }
            }
        }

        // [ 데이터 ] /////////////////////////////////////////////////////////////////////
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string asciiString = ReadAscii(serialPort1); // 바이트를 아스키로 변환

            HandleBarcodeData(asciiString); // 읽은 값을 넘김
        }

        private void HandleBarcodeData(string asciiString)
        {
            Vo parsedVo = ParseBarcode(asciiString); // 파싱해서 객체에 저장

            // UI용
            UiVer = parsedVo;

            // UI 업데이트 (UI 스레드에서 실행)
            this.Invoke(new Action(() => UpdateUI(UiVer)));

            ////////////////////////////////////////////////
            
            // DB용
            DbVer = new Vo
            {
                GTIN = parsedVo.GTIN,
                Exp = parsedVo.Exp,
                Lot = parsedVo.Lot,
                Serial = parsedVo.Serial
            };

            // DB 저장
            SaveToDatabase(DbVer);
        }

        private string ReadAscii(SerialPort port)
        {
            int bytes = port.BytesToRead; // 포트에 들어온 바이트를 가져와요
            byte[] buffer = new byte[bytes]; // 바이트 배열에 담아요
            port.Read(buffer, 0, bytes); // 버퍼를 바이트 크기만큼 읽어요
            return Encoding.ASCII.GetString(buffer); // 아스키로 인코딩 후 string으로 형변환해서 반환
        }

        // [ 파싱 ] /////////////////////////////////////////////////////////////////////
        private Vo ParseBarcode(string barcodeData)
        {
            Vo vo = new Vo();

            // FNC1(ASCII 29) 기준으로 분리
            string[] parts = barcodeData.Split('\x1D');

            foreach (var part in parts)
            {
                if (string.IsNullOrWhiteSpace(part))
                {
                    continue;
                }

                int index = 0;

                while (index < part.Length)
                {
                    // code = 식별자
                    string code = part.Substring(index, Math.Min(2, part.Length - index));
                    index += 2;

                    if (code == "01") // GTIN (고정 14자리)
                    {
                        int len = Math.Min(14, part.Length - index);
                        vo.GTIN = part.Substring(index, len);
                        index += len;
                    }
                    else if (code == "17") // 유효기간 (고정 6자리)
                    {
                        int len = Math.Min(6, part.Length - index);
                        vo.Exp = part.Substring(index, len);
                        index += len;
                    }
                    else if (code == "10") // LOT (가변, 나머지 전체)
                    {
                        vo.Lot = part.Substring(index);
                        break;
                    }
                    else if (code == "21") // SERIAL (가변, 나머지 전체)
                    {
                        vo.Serial = part.Substring(index);
                        break;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            return vo;
        }

        // 다음 AI 위치 찾는 헬퍼 메서드
        private int FindNextAIIndex(string part, int start)
        {
            // 다음 AI가 시작되는 위치 찾기 (보통 숫자 2자리로 시작)
            for (int i = start; i < part.Length - 1; i++)
            {
                if (char.IsDigit(part[i]) && char.IsDigit(part[i + 1]))
                {
                    string possibleAi = part.Substring(i, 2);
                    if (possibleAi == "01" || possibleAi == "10" || possibleAi == "17" || possibleAi == "21")
                        return i;
                }
            }

            return part.Length; // 다음 AI가 없으면 끝까지 읽기
        }


        // [ UI 바인딩 ] /////////////////////////////////////////////////////////////////////

        private void UpdateUI(Vo vo)
        {
            textBoxGtin.Text = vo.GTIN;
            textBoxExp.Text = vo.Exp;
            textBoxLot.Text = vo.Lot;
            textBoxSerial.Text = vo.Serial;

            // 디버깅용
            Console.WriteLine($"GTIN   : {vo.GTIN}");
            Console.WriteLine($"EXP    : {vo.Exp}");
            Console.WriteLine($"LOT    : {vo.Lot}");
            Console.WriteLine($"SERIAL : {vo.Serial}");
        }

        // [ DB ] /////////////////////////////////////////////////////////////////////
        private void btnSend_Click(object sender, EventArgs e)
        {
            SaveToDatabase(DbVer);
        }

        private void SaveToDatabase(Vo vo)
        {
            // DB 연결 및 INSERT
        }

    }
}