소프트웨어/C# & ASP.NET

Windows Mobile in C# 강좌 Lab 2 - GPS 사용법(2)

falconer 2009. 11. 26. 16:14

Windows Mobile in C#
  • 본 강좌는 Windows Mobile 6 세미나의 자료를 기반으로 제작 하였습니다.
  • Microsoft Visual Studio 2008 C# / Windows Mobile 6 Professional SDK


안녕하세요^^ Windows Mobile in C# 세번째 강좌 시간 입니다.

연재강좌.. 어때요?? 열심히 한다고 만들기는 했는데.. 도움이 좀 되시나요?? :)

도움이 되었길 기도하면서... 지난시간에 이어 GPS 사용법에 대해 이번 시간을 체워 볼까 합니다.

지난 강좌에서 가상 GPS 기능인 FakeGPS를 연결하는 방법과 간단한 GPS 좌표를 출력하는 법을 배웠습니다.

오늘은 좀더 구체적인 GPS 사용법에 대해 알아 볼건데요.. 이해하기 쉽게 설명 하도록 노력해 보겠습니다..^^;;

1 Form 생성

1.1 FormGpsInfo

  • 지난 시간에 FormGpsInfo 폼에 TextBox와 Button을 이용하여 GPS 좌표를 출력 하였는데요.. 이번 시간에는 TextBox만을 사용하여 가상 GPS에서 보내는 실시간 정보를 출력 해보도록 하겠습니다.

  • 우선 FormGpsInfo 폼에 도구상자의 TextBox 컨트롤을 더블클릭하여 삽입 합니다.
  • 그리고 TextBox의 Name 속성을 "txtInfo"로 설정하고, Dock 속성을 "Fill", Multiline 속성을 "True"로 설정 합니다.

    1.JPG



2 참조 추가

2.1 GPSSingleton 추가

  • GPS Device를 사용하기 위해서 Windows Mobile 6 SDK의 라이브러리를 추가하시면 된다고 전 강좌에서 설명 했습니다. 모르시는 분들은 Lab2 강좌에서 확인 하시면 됩니다. ^^
  • 본 강좌에서는 GPS Operation을 access 하는 독립적인 클래스를 만들어서 사용할 것입니다. 즉, GPS 관련된 모든일을 이 클래스에 정의 하는 것이죠. 표현력 부족..ㅠ.ㅜ
  • 그럼 GPSSingleton.cs 를 새로 생성 합니다. 방법은 GPS 폴더에서 마우스 오른쪽을 클릭하여 "새 항목"을 추가 합니다. 템플릿은 "클래스"이고 파일 이름은 "GPSSingleton.cs" 로 설정 하시면 됩니다.

    2.JPG


  • 자.. 그럼 GPSSingleton.cs 클래스의 기능을 구현해 보도록 하겠습니다. 아래는 GPSSingleton.cs의 전체 코드 입니다.

public sealed class GPSSingleton : IDisposable
    {
        #region Fields
        private GpsDeviceState _LastDeviceState = null;               // GPS 디바이스 객체 생성 및 초기화
         private GpsPosition _LastValidPosition = null;                // GPS 위치 정보 객체 생성 및 초기화
         private DateTime _LastValidPositionTime = DateTime.MinValue;  // 시간 정보 객체 생성 및 초기화
         private bool _HasValidData = false; 
        private Gps _Gps = new Gps();                        
        private static volatile GPSSingleton _Instance;
        private static object _SyncRoot = new Object();
        #endregion Fields

        #region Properties
        public GpsServiceState LastDeviceState
        {
            get { return _LastDeviceState.DeviceState; }    //디바이스 상태
        }

        public GpsServiceState LastServiceState
        {
            get { return _LastDeviceState.ServiceState; }   //서비스 상태.
        }

        public String DriverFriendlyName
        {
            get { return _LastDeviceState.FriendlyName; }   //디바이스 장치명.
        }

        public GpsPosition LastValidPosition
        {
            get { return _LastValidPosition; }              //위치정보.
        }

        public DateTime LastValidPositionTime
        {
            get { return _LastValidPositionTime; }          //GPS로 받아본 국제 표준 시간.
        }

        public bool HasValidData
        {
            get { return _HasValidData; }
        }
        #endregion

        #region Private Constructor for Singleton

        private GPSSingleton()
        {
            _Gps.DeviceStateChanged += new DeviceStateChangedEventHandler(gps_DeviceStateChanged);
            _Gps.LocationChanged += new LocationChangedEventHandler(gps_LocationChanged);
            _Gps.Open();
        }
        #endregion

        #region Singleton
        public static GPSSingleton Instance
        {
            get
            {
                if (_Instance == null)
                {
                    lock (_SyncRoot)
                    {
                        if (_Instance == null)
                        {
                            _Instance = new GPSSingleton();
                        }
                    }
                }

                return _Instance;
            }
        }
        #endregion Singleton

        #region EventHandlers
        //EventArgs 클래스 상속 및 구현
        private void gps_LocationChanged(object sender, LocationChangedEventArgs args)
        {
            _LastValidPosition = args.Position;

            if (_LastValidPosition != null && _LastValidPosition.LatitudeValid == true 
                && _LastValidPosition.LongitudeValid == true)
            {
                _HasValidData = true;
                _LastValidPositionTime = DateTime.Now;
            }
        }

        //EventArgs 클래스 상속 및 구현
        private void gps_DeviceStateChanged(object sender, DeviceStateChangedEventArgs args)   
        {
            _LastDeviceState = args.DeviceState;

            if (_LastDeviceState != null && _LastDeviceState.DeviceState == GpsServiceState.Off 
                || _LastDeviceState.DeviceState == GpsServiceState.ShuttingDown 
                || _LastDeviceState.DeviceState == GpsServiceState.Unknown 
                || _LastDeviceState.DeviceState == GpsServiceState.Unloading)
            {
                _HasValidData = false;
            }
        }
        #endregion EventHandlers

        #region IDisposable Members

        public void Dispose()
        {
            if (_Gps.Opened)
            {
                _Gps.Close();    // GPS Close() 메소드.
                _Gps = null;
            }
        }

        #endregion
    }

  • 이제 코드가 점점 길어지기 시작하죠?? ㅎ 천천히 하나씩 살펴 볼 텐데요.. 아직 제가 실력이 많이 모자라서 틀린 부분이 있을 지도 모르겠네요.. 그래도 조금 양해 부탁 드리면서 진행을 시작 하겠습니다. 내용을 보시면 #region 을 사용하여 코드를 깔끔하게 정리 하였습니다. 저도 C#은 처음 접해보는 거라 #region가 뭔지 몰랐었는데.. 찾아보니 금방 나오네요..ㅎ #region에 대해서 궁금해 하시는 분들은 http://msdn.microsoft.com/ko-kr/library/ed8yd1ha(VS.80).aspx 이곳에서 확인 하시기 바랍니다..^^

  • #region Fields 부분을 보시면 사용 되어지는 변수들을 생성하고 초기화 시키는 코드를 보실 수있습니다.
  • #region Properties 은 get블럭으로 외부 각 필드값을 반환합니다. 소스를 보시면 대~~~충 어떤 값들인지 예상은 할 수 있겠죠?? 디바이스와 서비스 상태 및 디바이스 장치명, 위치, 시간 등에 대한 내용 입니다.

  • 아래의 코드는 이벤트 처리기 입니다. GPS 상태와 위치가 변경 되었을 때, GPS 객체에서 갱신 시켜주는 역할을 합니다. 그리고 GPS를 Open 시켜 줍니다. 여기서 쎈스가 있는 사람들은 눈치 채셨을지 모르겠네요.. Open() 메소드가 있다면 반드시 Close() 메소드가 존재 하겠죠?? 종료시에 Close() 해주 셔야 합니다^^

private GPSSingleton()
  {
      _Gps.DeviceStateChanged += new DeviceStateChangedEventHandler(gps_DeviceStateChanged);
      _Gps.LocationChanged += new LocationChangedEventHandler(gps_LocationChanged);
      _Gps.Open();
  }

  • GpsSingleton 클래스를 살펴 보았습니다. 어딘가 모르게 설명의 어색한 부분이 있는것 같은데...ㅡㅡ ㅎ

3 Source Code

3.1 FormGpsInfo

  • 이제 Form Code를 작성해 봐야겠죠?? 아래는 FormGpsInfo의 전체 Code 입니다.
namespace MobilityMetro2009
{
    public partial class FormGpsInfo : Form
    {
        GPSSingleton _gps = GPSSingleton.Instance;
        StringBuilder _info = new StringBuilder();

        public FormGpsInfo()
        {
            InitializeComponent();
            GpsUpdateTimer.Enabled = true;   // Timer 작동
        }

        void UpdateGPSInfo()
        {
            _info.Remove(0, _info.Length);

            try
            {
                // 디바이스 장치명, 디바이스 상태, 서비스 상태
                _info.AppendLine(_gps.DriverFriendlyName + " " + _gps.LastServiceState + ",
                " + _gps.LastDeviceState);

                // HasValidData는 사용할 수 있는 GPS Data 유무
                if (_gps.HasValidData == true)
                {
                    _info.AppendLine("Lat  (DD): " + _gps.LastValidPosition.Latitude);   // GPS 위도
                    _info.AppendLine("Long (DD): " + _gps.LastValidPosition.Longitude);  // GPS 경도

                    if (_gps.LastValidPosition.SatellitesInSolutionValid 
                    && _gps.LastValidPosition.SatellitesInViewValid 
                    && _gps.LastValidPosition.SatelliteCountValid)
                    {
                        // 사용중인 위성의 갯수, 탐지된 위성의 갯수
                        _info.Append("Satellite Count: "
                        + _gps.LastValidPosition.GetSatellitesInSolution().Length + "/" 
                        + _gps.LastValidPosition.GetSatellitesInView().Length + " (" 
                        + _gps.LastValidPosition.SatelliteCount + ")");

                        // Heading은 방향을 나타 냄.
                        if (_gps.LastValidPosition.HeadingValid == true)
                        {
                            _info.AppendLine(" - Heading: " + _gps.LastValidPosition.Heading.ToString());
                        }
                        else
                        {
                            _info.AppendLine(" - Heading: ");
                        }
                    }

                    // 속도 (단위는 knots 노트 이므로 km로 변경해서 사용)
                    if (_gps.LastValidPosition.SpeedValid == true)
                    {
                        _info.AppendLine("Speed: " + _gps.LastValidPosition.Speed.ToString("0.00") 
                        + " knots - " + (_gps.LastValidPosition.Speed * 1.85325).ToString("0.00") + "Km/h");
                    }

                    // 해수면 고도
                    if (_gps.LastValidPosition.SeaLevelAltitudeValid == true)
                    {
                        _info.AppendLine("Sea Level Altitude: " 
                        + _gps.LastValidPosition.SeaLevelAltitude.ToString() + " Meters");
                    }

                    string Inf = string.Empty;
                    string Separator = string.Empty;
                    
                    // fixType는 위치 계산 방법
                    if (_gps.LastValidPosition.fixType == FixType.XyD)
                    {
                        Inf += Separator + "Fix: 2D";
                        Separator = " - ";
                    }

                    else if(_gps.LastValidPosition.fixType == FixType.XyzD)
                    {
                        Inf += Separator + "Fix: 3D";
                        Separator = " - ";
                    }

                    // PDOP는 데이터의 신뢰도
                    if (_gps.LastValidPosition.PositionDilutionOfPrecisionValid == true)
                    {
                        Inf += Separator + "PDOP: " + 
                        ((_gps.LastValidPosition.PositionDilutionOfPrecision * 100) / 50).ToString("0")
                        + "%";
                        Separator = " - ";
                    }

                    // HDOP는 수평오차
                    if (_gps.LastValidPosition.HorizontalDilutionOfPrecisionValid == true)
                    {
                        Inf += Separator + "HDOP: " + 
                        ((_gps.LastValidPosition.HorizontalDilutionOfPrecision * 100) / 50).ToString("0")
                        + "%";
                        Separator = " - ";
                    }

                    // VDOP는 수직오차
                    if (_gps.LastValidPosition.VerticalDilutionOfPrecisionValid == true)
                    {
                        Inf += Separator + "VDOP: " + 
                        ((_gps.LastValidPosition.VerticalDilutionOfPrecision * 100) / 50).ToString("0")
                        + "%";
                        Separator = " - ";
                    }

                    _info.AppendLine(Inf);

                    // 
                    if (_gps.LastValidPosition.TimeValid)
                    {
                        _info.AppendLine("Time: " + _gps.LastValidPosition.Time.ToLocalTime().ToString());
                    }
                }
                else
                {
                    _info.AppendLine("No GPS Data Available.");

                    if (_gps.LastValidPosition.SatellitesInSolutionValid
                        && _gps.LastValidPosition.SatellitesInViewValid
                        && _gps.LastValidPosition.SatelliteCountValid)
                    {
                        _info.AppendLine("Satellite Count: " + 
                        _gps.LastValidPosition.GetSatellitesInSolution().Length + "/" +
                        _gps.LastValidPosition.GetSatellitesInView().Length + " (" +
                        _gps.LastValidPosition.SatelliteCount + ")");
                    }

                }

                txtInfo.Text = _info.ToString();
            }

            catch
            {
            }
        }

        // Timer 작동
        private void GpsUpdateTimer_Tick(object sender, EventArgs e)
        {
            UpdateGPSInfo();
        }

        // 종료 처리
        private void MnuBack_Click(object sender, EventArgs e)
        {
            GpsUpdateTimer.Enabled = false;
            this.Close();
        }
    }
}

  • 간단하게 Code에 주석으로 작성 하였습니다. GPS에 관해 사용 할 수 있는 정보들이 많이 있는데요. 저도 강좌를 위해 공부 하면서 어려운 점이 있네요. ㅠ.ㅜ 이보다 더 자세히 설명 하고 싶지만.. 너무 깊게 들어 가버리게 될까봐.. 간략하게 설명만 주석으로 추가 하였습니다^^;; 자 그럼 작성을 완료 하였으니 에뮬레이터로 실행 시켜 봐야겠죠??

4 실행 결과

  • 에뮬레이터 실행 방법은 이제 어느정도 아실 거라 생각 됩니다. 그럼 에뮬레이터 실행 결과 화면을 보시죠.
    6.JPG


  • 에뮬레이터로 테스트 해 보셨나요?? 위와 같은 내용을 확인 하셨으면 제대로 하셨습니다. 계속해서 GPS Data가 변하는 것을 보실 수 있을 거에요..

  • 다음 Lab 3 강좌는 SMS 문자 전송에 대한 강좌 입니다. 흠... GPS랑 전혀 연관이 없는데.. ㅋ SMS는 지금까지 만들어온 예제의 "연락처 추가" 기능을 통해 문자 전송하는 방법을 위해 Lab 3에서 배우는 것입니다. 그러니 연관성이 있겠죠?? 그럼 다음 강좌 시간에 뵙겠습니다~ 좋은 하루 보내세요~~ 감사합니다.


출처 : http://dforge.devpia.com/projects/studymobile/wiki/Lab2-1
http://dforge.devpia.com/projects/studymobile/wiki/

'소프트웨어 > C# & ASP.NET' 카테고리의 다른 글

문자열 비교 - 팁  (0) 2009.12.09
C# 프로그래밍 도구  (0) 2009.12.03
c# 개념잡기 - Generic  (0) 2009.11.25
get/set 메소드와 public 멤버변수  (0) 2009.11.25
한글 처리 문제 (EUC_KR, KSC5601-1992 )  (0) 2009.11.13