tanulas_sensor_API_programozas_tomoren - Fehér Krisztián honlapja

Fehér Krisztián weboldala
Fehér Krisztián weboldala
Tartalomhoz ugrás

tanulas_sensor_API_programozas_tomoren

Fehér Krisztián: Sensor API programozás tömören

Tartalomjegyzék
1 Előszó
1.1 A leírás célja és szerkezete
1.2 Követelmények
1.3 Letölthető programkódok
2 A szenzorprogramozás alapjai
2.1 A szenzorprogramozás eszközei
3 A Sensor API bemutatása
3.1 A csatolófelület elérése
3.2 Kapcsolat létrehozása eszközzel
3.3 Folyamatos lekérdezés
4 GPS tracker írása Windows-ra
4.1 A fejlécállomány (GNSS.H)
4.2 A főprogram
4.3 Teljes forráskódok
5 Helyadatok elérése böngészőből (JavaScript)

1 Előszó

A számítógépek érzékelő, adatfeldolgozó eszközök segítségével képesek adatokat szolgáltatni az őket körülvevő külvilágról.
Szenzorokat az élet számos területén alkalmaznak, például a közlekedésben, sportokban, kutatásokban és még sorolhatnánk.
Ez a leírás a szenzoradatok Windows operációs rendszer alatti elérését mutatja be a Sensor API segítségével, programozási eszközökkel.

1.1 A leírás célja és szerkezete

A leírás bevezető részében néhány példa bemutatásán túl a szenzorprogramozás eszközeiről és előfeltételeiről esik szó.
Ezután, mintegy esettanulmányként, egy USB-s helymeghatározó eszköz programozása kerül bemutatásra, több példaprogramon keresztül.
Végezetül pedig gyorsan megnézzük, hogy JavaScript segítségével, böngészőből milyen módon férhetünk hozzá helymeghatározó készülékünk mért adataihoz.

1.2 Követelmények

A leírás ismeretanyagának feldolgozásához és a kipróbáláshoz a C nyelv ismerete szükséges. Erősen ajánlott a jártasság a win32 programozásban is.
A leírás példái C / C++ programozási nyelven íródtak.

1.3 Letölthető programkódok

A leírásban található kódokat használó példaalkalmazások teljes forráskódja letölthető a következő weboldalról:




2 A szenzorprogramozás alapjai

2.1 A szenzorprogramozás eszközei

A szenzorprogramozás Windows operációs rendszereken alacsonyszintű és magasszintű szemléletet egyaránt tükröz.
A programozási csatolófelület (API) előnye, hogy eszközfüggetlen módon biztosítja a hozzáférést a külső eszközök által szolgáltatott mérési adatokhoz, így az eszközfüggő kódok magában az adott eszköz meghajtó programjában vannak.
A Sensor API a Windows 7 óta érhető el. Az API egy platformmá emelt eszköztár része.
A szenzorok használata Windows rendszereken külön engedélyhez kötött. Központilag is szabályozható a ‘Gépházban’ az ‘Alkalmazásengedélyek’ beállításokon keresztül, amire a leggyakoribb példa a tartózkodási helyhez történő hozzáférések engedélyezése.



A szenzorok működése privilegizált adahozzáférést is jelent egyben, ezért rendszergazdai szintű futtatás szükséges az ilyen programokhoz. A hozzáférés megadása futásidőben is lehetséges, az ilyen irányú kéréseket szintén támogatja és kezeli az API.


3 A Sensor API bemutatása

A Sensor API alapvető használatát konkrét példákon keresztül fogom bemutatni, esetünkben USB-s helymeghatározó eszközöket használva.
Nem törekszem kimerítő részletességre, elsősorban a gyakorlatiasságra koncentrálok. Az itt megszerzett tudást a későbbiekben már minden olvasó az igényeinek megfelelően képes lesz bővíteni.
A programok kifejlesztéséhez USB-s helymeghatározó eszközöket használtam, melyeket szokás GPS egereknek is nevezni, az alakjuk miatt. Az egyik régebbi eszköz egy Navilock NL-602U, a másik NL-8002U. Előbbi csak GPS, utóbbi pedig GLONASS műholdjeleket is tud venni és elbileg másodpercenként akár 18-szor is tudja frissíteni az adatokat.



Mindkét eszköz csúcsminőségű u-blox chipeket használ és stabil a meghajtóprogramjuk is.
A gyakorlat azt mutatja, hogy a gyártó weboldaláról letölthető u-center segédprogram nagyban meggyorsítja a műholdak megtalálásának az idejét, ezért indulásként érdemes lehet megvárni, amíg ez a program úgymond fixálja a műholdakat. Utána már be is zárhatjuk.



3.1 A csatolófelület elérése

Programjainkban az alábbi fejlécállományokra, illetve könyvtárakra lehet szükség:

Sensorsapi.h
Sensors.h
Initguid.h
FunctionDiscoveryKeys.h
Sensorsapi.lib
PortableDeviceGuids.lib

A .LIB kiterjesztésű könyvtárakat a Visual Studioban mindenképpen meg kell adnunk a ‘Linker’ – ‘Input’ – ‘Additional Dependencies’ beálltásoknál.



3.2 Kapcsolat létrehozása eszközzel

Mielőtt bármit is tudnánk kezdeni egy ilyen eszközzel, először is a program oldalán kapcsolatot kell létesíteni vele. Ez egy többlépcsős folyamat, lebonyolításához pedig a következő szenzorvonatkozású változókra lesz szükség.


// Segédváltozók
ISensorManager* pSensorManager = NULL;
ISensorCollection* pSensorColl = NULL;
ISensor* pSensor = NULL;
ISensorDataReport* pReport = NULL;


A konkrét szenzoradatok tárolására az alábbi változókat fogjuk felhasználni.


typedef struct sensor_details {
   char sensor_name[256];
   int real_index;
};
sensor_details szenzorinfok[10];

double sensor_longitude = 0;
double sensor_latitude = 0;
double sensor_altitude = 0;
double sensor_accuracy = 0;
double sensor_speed = 0;


A sensor_details adatszerkezet az összes elérhető szenzor nevét és sorszámát tartalmazni fogja az adott rendszeren. Elviekben ezek között többféle típusú szenzor is lehet, olyan is, amire nekünk nincsen szükségünk.
A többi, sensor_ kezdetű változó a majdan kiválasztott szenzortól lekérdezett konkrét téradatok tárolására használatos.
A szenzorral történő kapcsolat létrehozását egy külön függvényben fogjuk kezdeményezni. Ennek neve init_GNSS() lesz. Most ennek a működését fogjuk áttekinteni, lépésről-lépésre.
A példaprogramunk először is az imént említett adatszerkezet mezőit állítja be alapértelmezetten üres értékekre.


for (i = 0; i < 10; ++i)
{
   szenzorinfok[i].real_index = 0;
   strcpy_s(szenzorinfok[i].sensor_name, "");
}


Nagyon fontos, hogy a memóriába be legyen töltve a SENSORSAPI.DLL dinamikus könyvtár.


LoadLibraryA("SensorsApi.dll");


Ezt követően a CoInitializeEx() függvénnyel inicializálnunk kell a Windows COM elnevezésű kommunikációs könyvtárát. Az inicializáció sikerességét ellenőriznünk kell.


if (CoInitializeEx(NULL, COINIT_MULTITHREADED) != S_OK) return;


Innentől kezdve egy HRESULT típusú objektumot fogunk használni egy-egy rendszerhívás sikerességének a kezelésére. Ezt a segédváltozót globális változóként definiáljuk.


HRESULT hr = S_OK;


Ezt követően történik az ún. szenzormenedzser létrehozása:


hr = CoCreateInstance(CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSensorManager));


A CLSCTX kezdetű konstans az ún. végrehajtási kontextust adja meg, aminek a keretén belül a szenzor menedzser objektumunk fogja tengetni az idejét. Az esetünkben használt CLSCTX_INPROC_SERVER konstans azt adja meg, hogy a létrehozott objektumot egy DLL kezeli és ugyanabban a processzben fog létezni, ahonnan a CoCreateInstance() függvényt meghívták. Magyarul ez így egy általános beállítás. A függvény utolsó paramétere maga a szenzormenedzser objektum, ami esetünkben a pSensorManager.
A lehetséges CLSCTX konstansértékek egyébként a következők:

typedef enum tagCLSCTX {
 CLSCTX_INPROC_SERVER = 0x1,
 CLSCTX_INPROC_HANDLER = 0x2,
 CLSCTX_LOCAL_SERVER = 0x4,
 CLSCTX_INPROC_SERVER16 = 0x8,
 CLSCTX_REMOTE_SERVER = 0x10,
 CLSCTX_INPROC_HANDLER16 = 0x20,
 CLSCTX_RESERVED1 = 0x40,
 CLSCTX_RESERVED2 = 0x80,
 CLSCTX_RESERVED3 = 0x100,
 CLSCTX_RESERVED4 = 0x200,
 CLSCTX_NO_CODE_DOWNLOAD = 0x400,
 CLSCTX_RESERVED5 = 0x800,
 CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,
 CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,
 CLSCTX_NO_FAILURE_LOG = 0x4000,
 CLSCTX_DISABLE_AAA = 0x8000,
 CLSCTX_ENABLE_AAA = 0x10000,
 CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,
 CLSCTX_ACTIVATE_X86_SERVER = 0x40000,
 CLSCTX_ACTIVATE_32_BIT_SERVER,
 CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000,
 CLSCTX_ENABLE_CLOAKING = 0x100000,
 CLSCTX_APPCONTAINER = 0x400000,
 CLSCTX_ACTIVATE_AAA_AS_IU = 0x800000,
 CLSCTX_RESERVED6 = 0x1000000,
 CLSCTX_ACTIVATE_ARM32_SERVER = 0x2000000,
 CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION,
 CLSCTX_PS_DLL = 0x80000000
} CLSCTX;

A visszatérési érték ellenőrzésekor nem elég pusztán a sikerességet ellenőrizni, hanem hiba esetén azt az esetet is fel kell ismernünk, ha a Windows rendszeren le van tiltva a tartózkodási helyhez történő hozzáférés. Ezt az ERROR_ACCESS_DISABLED_BY_POLICY elnevezésű hiba jelzi.


if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DISABLED_BY_POLICY)) return;
if (hr != S_OK) return;


Ha minden jól megy, akkor a Windows ilyenkor meg szokta kérdezni első alkalommal, hogy biztosan engedélyezzük-e a helyadatokhoz történő hozzáférést a program számára. Erre természetesen igennel kell felelnük.
Ettől a ponttól kezdve már a pSensorManager objektum metódusait is hívni fogjuk, amikor is a rendszeren elérhető összes szenzor adatához hozzáférést kérünk. Erre külön objektumunk is lesz, egy ún szenzorgyűjtemény: pSensorColl. Ezt a GetSensorsByCategory() függvény meghívásával tudjuk beállítani. A függvény meghívásakor már meg kell adnunk a konkrét szenzorkategóriát is!


pSensorManager-> GetSensorsByCategory(SENSOR_CATEGORY_LOCATION, &pSensorColl);


Egy adott kategória többféle szenzortípust is felölelhet, esetünkben az alábbi helymeghatározásra használható szenzortípusokat különböztet meg a Windows:

SENSOR_TYPE_LOCATION_BROADCAST
SENSOR_TYPE_LOCATION_DEAD_RECKONING
SENSOR_TYPE_LOCATION_GPS
SENSOR_TYPE_LOCATION_LOOKUP
SENSOR_TYPE_LOCATION_OTHER
SENSOR_TYPE_LOCATION_STATIC
SENSOR_TYPE_LOCATION_TRIANGULATION

A SENSOR_CATEGORY_LOCATION kategória segítségével az alábbi adattípusok válhatnak elérhetővé:

SENSOR_DATA_TYPE_ADDRESS1
SENSOR_DATA_TYPE_ADDRESS2
SENSOR_DATA_TYPE_ALTITUDE_ANTENNA_SEALEVEL_METERS
SENSOR_DATA_TYPE_ALTITUDE_ELLIPSOID_ERROR_METERS
SENSOR_DATA_TYPE_ALTITUDE_ELLIPSOID_METERS
SENSOR_DATA_TYPE_ALTITUDE_SEALEVEL_ERROR_METERS
SENSOR_DATA_TYPE_ALTITUDE_SEALEVEL_METERS
SENSOR_DATA_TYPE_CITY
SENSOR_DATA_TYPE_COUNTRY_REGION
SENSOR_DATA_TYPE_DGPS_DATA_AGE
SENSOR_DATA_TYPE_DIFFERENTIAL_REFERENCE_STATION_ID
SENSOR_DATA_TYPE_ERROR_RADIUS_METERS
SENSOR_DATA_TYPE_FIX_QUALITY
SENSOR_DATA_TYPE_FIX_TYPE
SENSOR_DATA_TYPE_GEOIDAL_SEPARATION
SENSOR_DATA_TYPE_GPS_OPERATION_MODE
SENSOR_DATA_TYPE_GPS_SELECTION_MODE
SENSOR_DATA_TYPE_GPS_STATUS
SENSOR_DATA_TYPE_HORIZONAL_DILUTION_OF_PRECISION
SENSOR_DATA_TYPE_LATITUDE_DEGREES
SENSOR_DATA_TYPE_LONGITUDE_DEGREES
SENSOR_DATA_TYPE_MAGNETIC_HEADING_DEGREES
SENSOR_DATA_TYPE_MAGNETIC_VARIATION
SENSOR_DATA_TYPE_NMEA_SENTENCE
SENSOR_DATA_TYPE_POSITION_DILUTION_OF_PRECISION
SENSOR_DATA_TYPE_POSTALCODE
SENSOR_DATA_TYPE_SATELLITES_IN_VIEW
SENSOR_DATA_TYPE_SATELLITES_IN_VIEW_AZIMUTH
SENSOR_DATA_TYPE_SATELLITES_IN_VIEW_ELEVATION
SENSOR_DATA_TYPE_SATELLITES_IN_VIEW_ID
SENSOR_DATA_TYPE_SATELLITES_IN_VIEW_PRNS
SENSOR_DATA_TYPE_SATELLITES_IN_VIEW_STN_RATIO
SENSOR_DATA_TYPE_SATELLITES_USED_COUNT
SENSOR_DATA_TYPE_SATELLITES_USED_PRNS
SENSOR_DATA_TYPE_SPEED_KNOTS
SENSOR_DATA_TYPE_STATE_PROVINCE
SENSOR_DATA_TYPE_TRUE_HEADING_DEGREES
SENSOR_DATA_TYPE_VERTICAL_DILUTION_OF_PRECISION

Meg kell azonban jegyezni, hogy nem feltétlenül támogat minden szenzor minden adattípust.
Amint megvan a szenzorok gyűjteményének a lekérdezése, ellenőriznünk kell, hogy nem üres-e a lista.


ULONG sensor_count = 0;

hr = pSensorColl->GetCount(&sensor_count);

if (SUCCEEDED(hr))
{
   if (sensor_count < 1) return;

}


Ha van legalább egy érvényes szenzor, akkor egy for ciklus segítségével elkezdjük lekérni az adatait. Ehhez a GetAt() függvényt használhatjuk.


pSensorColl->GetAt(i, &pSensor);


Ezek után még további ellenőrzéseket kell végrehajtanunk, mielőtt a mérési értékeket kinyerhetnénk.
Az első ilyen ellenőrzés a szenzor státuszának a lekérése.


SensorState state = SENSOR_STATE_NOT_AVAILABLE;
hr = pSensor->GetState(&state);


Ezután megnézzük, hogy ez a státusz véletlenül nem a SENSOR_STATE_ACCESS_DENIED érték-e. Ez az érték jelzi ugyanis, ha a Windows-ban még nem engedélyezték ennek a szenzornak a lekérdezését ehhez az alkalmazáshoz. Ebben az esetben a programból explicit módon kezdeményezhetjük a hozzáférés endélyezését.


if (state == SENSOR_STATE_ACCESS_DENIED)
{
hr = pSensorManager->RequestPermissions(0, pSensorColl, FALSE);

if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) ||
       hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) return;
}


Az értékeket át kell töltenünk a pReport adatszerkezetbe. Ez még mindig csak egy segédobjektum, de kitartás, már közel járunk a szenzorértékekhez!


hr = pSensor->GetData(&pReport);


Az általánosabb tulajdonságokat a GetProperty() függvény segítségével tudjuk kiolvasni. Legelőször a szenzor nevét (modell név) kérdezzük le.


PROPVARIANT var = {};

hr = pSensor->GetProperty(SENSOR_PROPERTY_MODEL, &var);
szenzorinfok[sensor_current_count].real_index=i;
{
int hossz = wcslen(var.bstrVal) + 1;

WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, szenzorinfok[sensor_current_count].sensor_name, hossz, NULL, NULL);

printf_s("%s\n", szenzorinfok[sensor_current_count].sensor_name);
}


A tényleges szenzorértékek kinyerésére a GetSensorValue() függvény szolgál, itt kell megadnunk a kívánt adat típusát is (lásd a listát fentebb). Ezek az adatok már valóban a szenzor által szolgáltatott értékek kesznek. Az alábbi példában a helymeghatározó eszköz pontosságának értékét kaphatjuk meg.
Az érték double típusú adat, amit még szöveggé kell konvertálni, mielőtt kiírathatnánk a képernyőre. Ehhez hasonlóan kell eljárni a többi érték esetén is.


hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_ERROR_RADIUS_METERS, &var);
sensor_accuracy = var.dblVal;

char szoveg[1024];
sprintf_s(szoveg, "%f", sensor_accuracy);
strcpy_s(szoveg, "\r\nAccuracy: ");


Fontos megjegyezni, hogy a pSensorManager stb. segédobjektumok által lefoglalt erőforrásokat illik felszabadítani, ha már nincsen rájuk szükség. Ezt a Release() tagfüggvénnyel tehetjük meg.

Példa:

pSensorManager->Release();

Az alábbiakban egy teljes program (PELDA_01) forráskódját találjuk. Az átláthatóság kedvéért az egyes szenzorértékek kiolvasását és megjelenítését, valamint az adatobjektumok által lefoglalt memóriaterületek felszabadítását külön segédfüggvényekbe szerveztem ki.


#pragma once
#include <Sensorsapi.h>
#include <Sensors.h>
#include <initguid.h>
#include <FunctionDiscoveryKeys.h>
#include <propkeydef.h>
#include <propvarutil.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>

HRESULT hr = S_OK;

// Segédváltozók
ISensorManager* pSensorManager = NULL;
ISensorCollection* pSensorColl = NULL;
ISensor* pSensor = NULL;
ISensorDataReport* pReport = NULL;

typedef struct sensor_details {
char sensor_name[256];
int real_index;
};
sensor_details szenzorinfok[10];

ULONG sensor_count = 0;
double sensor_longitude = 0;
double sensor_latitude = 0;
double sensor_altitude = 0;
double sensor_accuracy = 0;
double sensor_speed = 0;

//Függvények
template <class T> void SafeRelease(T** ppT);
void init_GNSS(void);
void release_GNSS(void);
void get_sensor_values(int sensor_index);
void display_sensor_values(void);

int main()
{
init_GNSS();
//folyamatos frissítéshez
//while (1)
//{
// get_sensor_values(0);
// display_sensor_values();
// Sleep(1000);
// system("cls");
//}
}

//Inicializálás
void init_GNSS(void)
{
int i;
int sensor_current_count = 0;

for (i = 0; i < 10; ++i)
{
 szenzorinfok[i].real_index = 0;
 strcpy_s(szenzorinfok[i].sensor_name, "");
}
LoadLibraryA("SensorsApi.dll");
//COM könyvtár inicializalasa
if (CoInitializeEx(NULL, COINIT_MULTITHREADED) != S_OK) return;
// A szenzor menedzser beállítása
hr = CoCreateInstance(CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSensorManager));

if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DISABLED_BY_POLICY)) return;
if (hr != S_OK) return;

// Szenzoradatok lelkérése
hr = pSensorManager->GetSensorsByCategory(SENSOR_CATEGORY_LOCATION, &pSensorColl);
if (SUCCEEDED(hr))
{
 hr = pSensorColl->GetCount(&sensor_count);

 if (SUCCEEDED(hr))
 {
  if (sensor_count < 1) return;
 }
}

for (i = 0; i < sensor_count; ++i)
{
 //A listában soron következő szenzor lekérése
 if (SUCCEEDED(hr)) hr = pSensorColl->GetAt(i, &pSensor);
 printf_s("%i. szenzor adatai:\n",i+1);

 if (SUCCEEDED(hr))
 {
  // Szenzor állapotűnak ellenőrzése
  SensorState state = SENSOR_STATE_NOT_AVAILABLE;
  hr = pSensor->GetState(&state);

  if (SUCCEEDED(hr))
  {
   if (state == SENSOR_STATE_ACCESS_DENIED)
   {
    hr = pSensorManager->RequestPermissions(0, pSensorColl, FALSE);

    if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) ||
     hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) return;
   }
   else
   {
    if (SUCCEEDED(hr))
    {
     // Szenzor értékeinek kinyerése
     hr = pSensor->GetData(&pReport);
    }
    if (SUCCEEDED(hr))
    {
     PROPVARIANT var = {};

     hr = pSensor->GetProperty(SENSOR_PROPERTY_MODEL, &var);
     szenzorinfok[sensor_current_count].real_index = i;
     {
      int hossz = wcslen(var.bstrVal) + 1;
      WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, szenzorinfok[sensor_current_count].sensor_name, hossz, NULL, NULL);
      printf_s("%s\n", szenzorinfok[sensor_current_count].sensor_name);
     }
     get_sensor_values(i);
     display_sensor_values();
     ++sensor_current_count;
    }
   }
  }
 }
}
}

//Szenzoradatok lekérdezése
void get_sensor_values(int sensor_index)
{
SensorState state = SENSOR_STATE_NOT_AVAILABLE;
hr = pSensor->GetState(&state);
if (SUCCEEDED(hr)) hr = pSensorColl->GetAt(szenzorinfok[sensor_index].real_index, &pSensor);
if (SUCCEEDED(hr)) hr = pSensor->GetData(&pReport);
if (SUCCEEDED(hr))
{
 PROPVARIANT var = {};

 hr = pSensor->GetProperty(SENSOR_PROPERTY_MODEL, &var);
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_ERROR_RADIUS_METERS, &var);
 sensor_accuracy = var.dblVal;
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_LONGITUDE_DEGREES, &var);
 sensor_longitude = var.dblVal;
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_LATITUDE_DEGREES, &var);
 sensor_latitude = var.dblVal;
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_ALTITUDE_ELLIPSOID_METERS, &var);
 sensor_altitude = var.dblVal;
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_SPEED_METERS_PER_SECOND, &var);
 sensor_speed = var.dblVal;
}
}

//Szenzoradatok kiírása
void display_sensor_values(void)
{
char szoveg[1024], szoveg2[64];
strcpy_s(szoveg, "Sensor values:");
sprintf_s(szoveg2, "%f", sensor_accuracy);
strcat_s(szoveg, "\r\nAccuracy: "); strcat_s(szoveg, szoveg2);
sprintf_s(szoveg2, "%f", sensor_longitude);
strcat_s(szoveg, "\r\nLongitude: "); strcat_s(szoveg, szoveg2);
sprintf_s(szoveg2, "%f", sensor_latitude);
strcat_s(szoveg, "\r\nLatitude: "); strcat_s(szoveg, szoveg2);
sprintf_s(szoveg2, "%f", sensor_altitude);
strcat_s(szoveg, "\r\nAltitude: "); strcat_s(szoveg, szoveg2);
sprintf_s(szoveg2, "%f", sensor_speed);
strcat_s(szoveg, "\r\nSpeed: "); strcat_s(szoveg, szoveg2);
printf_s("%s\n\n", szoveg);
}

//Memóriaterületek felszabadítása
void release_GNSS(void)
{
SafeRelease(&pSensorManager);
SafeRelease(&pSensorColl);
SafeRelease(&pSensor);
SafeRelease(&pReport);
}

template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
 (*ppT)->Release();
 *ppT = NULL;
}
}


A program kimenete:



3.3 Folyamatos lekérdezés

Mivel a szenzoradatok lekérdezését és megjelenítését már ezt megelőzően külön függvényekbe szerveztük ki, így nagyon egyszerűen kibővíthető a program úgy, hogy az folyamatosan, például másodpercenként automatikusan elvégezze a szenzorértékek kiírását.


while (1)
{
 get_sensor_values(0);
 display_sensor_values();
 Sleep(1000);
 system("cls");
}


Erre alapozva akár GPS tracker programot is írhatunk Windows-ra. Pontosan ezt fogom bemutatni a következő fejezetben. 



4 GPS tracker írása Windows-ra

Végezetül egy ablakos GPS tracker program megírását is bemutatom (PELDA_02). Ez az alkalmazás egy CSV fájlba folyamatosan el is menti az aktuális helyadatokat. Az ismétlődő naplózási műveleteket egy időzítő (timer) segítségével fogjuk ütemezni.
A program ablaka így néz ki:



Magára az ablakos Windows programok írására nem térek ki, de a teljes vonatkozó forráskód lentebb így is megtalálható lesz. Akiket ez közelebbről érdekel, ‘A Windows keményvonalas programozása’ c. leírásomat ajánlom tanulmányozásra. Ezért itt csak a legfontosabb mozzanatok leírására térek ki.

4.1 A fejlécállomány (GNSS.H)

A szenzorspecifikus, ill. a naplózással kapcsolatos függvényeket egy külön fejlécállományba, a GNSS.H fájlba szervezzük ki.

Ezek a függvények:


template <class T> void SafeRelease(T** ppT);
void init_GNSS(void);
void release_GNSS(void);
void get_sensor_values(int sensor_index);
void display_sensor_values(HWND display_objektum);
void log_init(void);
void log_location_data(void);


Ezek a függvények már ismerősek lesznek az előző példaprogramból is.
A display_sensor_values() függvény utolsó sora más lesz, mégpedig erről:


printf_s("%s\n\n", szoveg);


erre fog változni:


SetWindowTextA(display_objektum, szoveg);


A program ugyanúgy megjeleníti a koordinátákat stb., csak nem a terminálablak kimenetére, hanem az ablak egyik szövegdobozába fogja kiírni őket.
Szintén a fejlécállomány tartalmazza a selected_sensor_index és a sensor_update_active segédváltozókat, melyek az éppen kiválasztott szenzor indexét, ill. az időzítő bekapcsolását mutatják.
A naplózás két függvényben lesz megvalósítva. Az első, a log_init() függvény magát a naplófájlt hozza létre, a CSV fájl oszlopneveivel. A naplófájl neve: GPS_DATA.TXT lesz. Ezt a függvényt a program futásának legelején, egészen pontosan a programablak létrehozásakor fogja a program meghívni.
A második függvény, a log_location_data() végzi az érdemi, folyamatos naplózást.


void log_init(void)
{
fopen_s(&file1, "GPS_data.txt", "wt");
if (file1 == NULL) return;
fprintf_s(file1, "ACCURACY,LONGITUDE,LATITUDE,ALTITUDE,SPEED (M/S)\r\n");
fclose(file1);
}

void log_location_data(void)
{
char szoveg[1024], szoveg2[64];
fopen_s(&file1, "GPS_data.txt", "at");
if (file1 == NULL) return;
strcpy_s(szoveg, ""); strcpy_s(szoveg2, "");
sprintf_s(szoveg2, "%f", sensor_accuracy);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, ",");
sprintf_s(szoveg2, "%f", sensor_longitude);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, ",");
sprintf_s(szoveg2, "%f", sensor_latitude);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, ",");
sprintf_s(szoveg2, "%f", sensor_altitude);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, ",");
sprintf_s(szoveg2, "%f", sensor_speed);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, "\r\n");
fprintf_s(file1,"%s",szoveg);
fclose(file1);
}


Példa a naplófájl tartalmára:

ACCURACY,LONGITUDE,LATITUDE,ALTITUDE,SPEED (M/S)
7.547185,19.455912,47.225048,205.400000,1.000000
7.409453,19.455908,47.225049,204.800000,1.000000
7.324616,19.455908,47.325049,204.400000,2.000000
7.186793,19.455907,47.325050,204.000000,3.000000

Az így gyűjtött adatok beimportálhatóak más alkalmazásokba, de akár egy táblázatkezelő program segítségével is értékes elemzéseket lehet végezni és statistikákat lehet készíteni.

4.2 A főprogram

A legfontosabb műveleteket ez a három függvény végzi:


void Main_Close(void);
void update_sensor_list(void);
void apply_sensor_update_interval(void);


Az első függvény az időzítő leállítását és a szenzorobjektumok felszabadítását végzi el:


void Main_Close(void)
{
KillTimer(GNSS_Setup_Window, ID_TIMER1);
release_GNSS();
}


A program egy kombinált listadoboz elemeiként kínál fel minden, a rendszeren éppen aktív helymeghatározó szenzort kiválasztásra.
A listadoboz vezérlő neve: ComboBox_Sensorlist
A lista feltöltését az update_sensor_list() függvény végzi el, szintén a program elindulásakor (közvetlenül a naplófájl inicializálása után), egyszeri alkalommal.
Amennyiben tehát egyik-másik szenzort lecsatlakoztatjuk a gépről, vagy éppen újat csatlakoztatunk és szeretnénk majd ebben a listában kiválaszthatóvá tenni, akkor mindenképpen újra kell indítanunk az alkalmazást.


void update_sensor_list(void)
{
int i;
SendMessageA(ComboBox_Sensorlist, CB_RESETCONTENT, 0, 0);
SendMessageA(ComboBox_Sensorlist, CB_ADDSTRING, 0, (LPARAM)"Select a GNSS sensor");

for (i = 0; i < sensor_current_count; ++i)
{
    SendMessageA(ComboBox_Sensorlist, CB_ADDSTRING, 0, (LPARAM)szenzorinfok[i].sensor_name);
}

SendMessageA(ComboBox_Sensorlist, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
}


Amikor a listából kiválasztunk egy helymeghatározó eszközt, akkor egyszeri alkalommal megjelenítjük az éppen általa szolgáltatott adatokat a display_sensor_values() függvénnyel.


case WM_COMMAND:
if (LOWORD(wParam) == OBJ_ID104 && HIWORD(wParam) == CBN_SELCHANGE)
{
 selected_sensor_index =
  SendMessageA(ComboBox_Sensorlist, CB_GETCURSEL,
   (WPARAM)0, (LPARAM)0);

 if (selected_sensor_index == 0)
 { selected_sensor_index = -1;   
   KillTimer(GNSS_Setup_Window, ID_TIMER1); }
 else selected_sensor_index -= 1;

 if (selected_sensor_index > -1)
 {
  get_sensor_values(selected_sensor_index);
  display_sensor_values(Sensor_live_data);
 }   
}


Fontos: amennyiben az eszköz még nem állt rá a látható műholdakra, akkor itt sem fognak megjelenni adatok. A “FIX” állapot eléréséről tehát meg kell győződnünk előtte!
Amennyiben az ‘APPLY’ nyomógombra kattintunk, akkor aktiválhatjuk a tulajdonképpeni track-elést. Ez kiolvassa az egyébként szabadon megadható kívánt frissítési időtartamot ezredmásodpercben és elindítja az ennek megfelelő ütemezőt.


void apply_sensor_update_interval(void)
{
if (selected_sensor_index == -1) return;
char szoveg[16];
int upd_interval;

GetWindowTextA(Sensor_upd_intvl, szoveg,
 GetWindowTextLengthA(Sensor_upd_intvl) + 1);

upd_interval = atoi(szoveg);

if (upd_interval < 100) upd_interval = 100;
if (sensor_update_active == 1)
   KillTimer(GNSS_Setup_Window, ID_TIMER1);
else sensor_update_active = 1;
SetTimer(GNSS_Setup_Window, ID_TIMER1, upd_interval, (TIMERPROC)NULL);
}


Az ütemező minden aktiváláskor lekéri az aktuális adatokat a szenzortól, megjeleníti őket és kiírja a naplófájlba.


case WM_TIMER:
 switch (wParam)
 {
 case ID_TIMER1:
  get_sensor_values(selected_sensor_index);
  display_sensor_values(Sensor_live_data);
  log_location_data();
  break;
 }


A program vonatkozó működését a fent taglalt kódrészek végzik. Alább megtalálható a teljes forráskód is. A bizonyára izgalmas kipróbáláshoz sok sikert kívánok az olvasónak!

A program futtatás közben:



4.3 Teljes forráskódok


GNSS.h

#pragma once
#include <Sensorsapi.h>
#include <Sensors.h>
#include <initguid.h>
#include <FunctionDiscoveryKeys.h>
#include <propkeydef.h>
#include <propvarutil.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

HRESULT hr = S_OK;
FILE* file1;

// Segádváltozók
ISensorManager* pSensorManager = NULL;
ISensorCollection* pSensorColl = NULL;
ISensor* pSensor = NULL;
ISensorDataReport* pReport = NULL;

int selected_sensor_index = -1, sensor_current_count = 0, sensor_update_active = -1;
double sensor_longitude = 0, sensor_latitude = 0, sensor_altitude = 0, sensor_accuracy = 0, sensor_speed = 0;

typedef struct sensor_details {
char sensor_name[256];
int real_index;
};
sensor_details szenzorinfok[10];

//Segédfüggvények
template <class T> void SafeRelease(T** ppT);
void init_GNSS(void);
void release_GNSS(void);
void get_sensor_values(int sensor_index);
void display_sensor_values(HWND display_objektum);
void log_init(void);
void log_location_data(void);

//Inicializálás
void init_GNSS(void)
{
int i;
int sensor_count = 0;
for (i = 0; i < 10; ++i)
{
 szenzorinfok[i].real_index = 0;
 strcpy_s(szenzorinfok[i].sensor_name, "");
}
LoadLibraryA("SensorsApi.dll");
if (CoInitializeEx(NULL, COINIT_MULTITHREADED) != S_OK) return;
// Szenzormenedzser létrehozása
hr = CoCreateInstance(CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSensorManager));

if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DISABLED_BY_POLICY)) return;

// Szenzorok lekérése
hr = pSensorManager->GetSensorsByCategory(SENSOR_CATEGORY_LOCATION, &pSensorColl);
if (SUCCEEDED(hr))
{
 ULONG ulCount = 0;

 hr = pSensorColl->GetCount(&ulCount);

 if (SUCCEEDED(hr))
 {
  if (ulCount < 1)
  {
   sensor_count = 0;
   return;
  }
  else
  {
   sensor_count = ulCount;
   if (sensor_count > 10) sensor_count = 10;
  }
 }
}

for (i = 0; i < sensor_count; ++i)
{
 if (SUCCEEDED(hr))
 {
  hr = pSensorColl->GetAt(i, &pSensor);
 }

 if (SUCCEEDED(hr))
 {
  SensorState state = SENSOR_STATE_NOT_AVAILABLE;
  hr = pSensor->GetState(&state);

  if (SUCCEEDED(hr))
  {
   if (state == SENSOR_STATE_ACCESS_DENIED)
   {
    hr = pSensorManager->RequestPermissions(0, pSensorColl, FALSE);

    if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) ||
     hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) return;
   }
   else
   {
    if (SUCCEEDED(hr))
    {
     hr = pSensor->GetData(&pReport);
    }
    if (SUCCEEDED(hr))
    {
     PROPVARIANT var = {};

     hr = pSensor->GetProperty(SENSOR_PROPERTY_MODEL, &var);
     szenzorinfok[sensor_current_count].real_index = i;
     {
      int hossz = wcslen(var.bstrVal) + 1;
      WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, szenzorinfok[sensor_current_count].sensor_name, hossz, NULL, NULL);
     }
     ++sensor_current_count;
    }
   }
  }
 }
}

return;
}

//Memóriaterületek felszabadítása
void release_GNSS(void)
{
SafeRelease(&pSensorManager);
SafeRelease(&pSensorColl);
SafeRelease(&pSensor);
SafeRelease(&pReport);
}

template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
 (*ppT)->Release();
 *ppT = NULL;
}
}

//Szenzorértékek lekérdezése
void get_sensor_values(int sensor_index)
{
SensorState state = SENSOR_STATE_NOT_AVAILABLE;
hr = pSensor->GetState(&state);
if (SUCCEEDED(hr)) hr = pSensorColl->GetAt(szenzorinfok[sensor_index].real_index, &pSensor);
if (SUCCEEDED(hr)) hr = pSensor->GetData(&pReport);
if (SUCCEEDED(hr))
{
 PROPVARIANT var = {};

 hr = pSensor->GetProperty(SENSOR_PROPERTY_MODEL, &var);
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_ERROR_RADIUS_METERS, &var);
 sensor_accuracy = var.dblVal;
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_LONGITUDE_DEGREES, &var);
 sensor_longitude = var.dblVal;
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_LATITUDE_DEGREES, &var);
 sensor_latitude = var.dblVal;
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_ALTITUDE_ELLIPSOID_METERS, &var);
 sensor_altitude = var.dblVal;
 if (SUCCEEDED(hr)) hr = pReport->GetSensorValue(SENSOR_DATA_TYPE_SPEED_METERS_PER_SECOND, &var);
 sensor_speed = var.dblVal;
}
}

//Szenzorértékek megjelenításe
void display_sensor_values(HWND display_objektum)
{
char szoveg[1024], szoveg2[64];
strcpy_s(szoveg, "Sensor values:");
sprintf_s(szoveg2, "%f", sensor_accuracy);
strcat_s(szoveg, "\r\nAccuracy: "); strcat_s(szoveg, szoveg2);
sprintf_s(szoveg2, "%f", sensor_longitude);
strcat_s(szoveg, "\r\nLongitude: "); strcat_s(szoveg, szoveg2);
sprintf_s(szoveg2, "%f", sensor_latitude);
strcat_s(szoveg, "\r\nLatitude: "); strcat_s(szoveg, szoveg2);
sprintf_s(szoveg2, "%f", sensor_altitude);
strcat_s(szoveg, "\r\nAltitude: "); strcat_s(szoveg, szoveg2);
sprintf_s(szoveg2, "%f", sensor_speed);
strcat_s(szoveg, "\r\nSpeed: "); strcat_s(szoveg, szoveg2);
SetWindowTextA(display_objektum, szoveg);
}

//Naplózás inicializálása
void log_init(void)
{
fopen_s(&file1, "GPS_data.txt", "wt");
if (file1 == NULL) return;
fprintf_s(file1, "ACCURACY,LONGITUDE,LATITUDE,ALTITUDE,SPEED (M/S)\r\n");
fclose(file1);
}

//Naplózás
void log_location_data(void)
{
char szoveg[1024], szoveg2[64];
fopen_s(&file1, "GPS_data.txt", "at");
if (file1 == NULL) return;
strcpy_s(szoveg, ""); strcpy_s(szoveg2, "");
sprintf_s(szoveg2, "%f", sensor_accuracy);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, ",");
sprintf_s(szoveg2, "%f", sensor_longitude);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, ",");
sprintf_s(szoveg2, "%f", sensor_latitude);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, ",");
sprintf_s(szoveg2, "%f", sensor_altitude);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, ",");
sprintf_s(szoveg2, "%f", sensor_speed);
strcat_s(szoveg, szoveg2); strcat_s(szoveg, "\r\n");
fprintf_s(file1,"%s",szoveg);
fclose(file1);
}

PELDA02.CPP

#include <windows.h>
#include <commdlg.h>
#include <commctrl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <commctrl.h>
#include "GNSS.h"

#define ID_TIMER1 999 //ütemezés intervalluma
//GUI vezérlők azonosítói
#define OBJ_ID101 101
#define OBJ_ID104 104
#define OBJ_ID105 105
#define OBJ_ID106 106

/*globális változók a GUI-hoz*/
#define HIBA_00 TEXT("Error:Window couldn't be registered.")
#define IDC_STATIC -1
#define LVM_SELECTED 2
#define WINSTYLE_NORMAL (WS_OVERLAPPED | WS_SYSMENU | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX)
#define WINSTYLE_DIALOG (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU)
#define WINSTYLE_NONESIZEABLE (WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX)
#define WINSTYLE_CAPTIONONLY (WS_DLGFRAME)
#define WINSTYLE_NOCAPTON (WS_POPUP)

HINSTANCE hInstGlob;
int SajatiCmdShow;

LRESULT CALLBACK WndProc_GNSS_Setup(HWND, UINT, WPARAM, LPARAM);

HWND GNSS_Setup_Window;
HWND GNSSConfig_Button;
HWND Sensor_upd_intvl;
HWND Apply_upd_intvl;
HWND Stop_update;
HWND ComboBox_Sensorlist;
HWND Sensor_live_data;

//Segédfüggvények
void ShowMessage(LPCTSTR uzenet, LPCTSTR cim, HWND kuldo);
void Main_Close(void);
void update_sensor_list(void);
void apply_sensor_update_interval(void);

//Főprogram
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("StdWinClassName");
HWND hwnd;
MSG msg;
WNDCLASS wndclass3;
LoadLibraryA("COMCTL32.DLL");
SajatiCmdShow = iCmdShow;
hInstGlob = hInstance;

init_GNSS();

wndclass3.style = CS_HREDRAW | CS_VREDRAW;
wndclass3.lpfnWndProc = WndProc_GNSS_Setup;
wndclass3.cbClsExtra = 0;
wndclass3.cbWndExtra = 0;
wndclass3.hInstance = hInstance;
wndclass3.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass3.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass3.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass3.lpszMenuName = NULL;
wndclass3.lpszClassName = TEXT("WIN3");

if (!RegisterClass(&wndclass3))
{
 MessageBox(NULL, HIBA_00, TEXT("Program Start"), MB_ICONERROR); return 0;
}

GNSS_Setup_Window = CreateWindow(TEXT("WIN3"),
 TEXT("GNSS tracker"),
 WINSTYLE_DIALOG,
 50,
 400,
 435,
 314,
 NULL,
 NULL,
 hInstance,
 NULL);

ShowWindow(GNSS_Setup_Window, SajatiCmdShow);
UpdateWindow(GNSS_Setup_Window);

while (GetMessage(&msg, NULL, 0, 0))
{
 TranslateMessage(&msg);
 DispatchMessage(&msg);
}
return msg.wParam;
}

//Ablak eseménykezelője
LRESULT CALLBACK WndProc_GNSS_Setup(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int s1;
HDC hdc;
PAINTSTRUCT ps;
RECT rect;

switch (message)
{
case WM_CREATE:
 /*Initializing*/;
 ComboBox_Sensorlist = CreateWindow(TEXT("combobox"), NULL
  , WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST, 50, 20, 320, 150
  , hwnd, (HMENU)(OBJ_ID104), ((LPCREATESTRUCT)lParam)->hInstance, NULL);
 Sensor_live_data = CreateWindow(TEXT("edit"), TEXT("")
  , WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_MULTILINE, 50, 55, 320, 130
  , hwnd, (HMENU)(OBJ_ID101), ((LPCREATESTRUCT)lParam)->hInstance, NULL);
 SetWindowTextA(Sensor_live_data, "Sensor live data");
 Sensor_upd_intvl = CreateWindow(TEXT("edit"), TEXT("1000")
  , WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 50, 200, 100, 20
  , hwnd, (HMENU)(IDC_STATIC), ((LPCREATESTRUCT)lParam)->hInstance, NULL);
 Apply_upd_intvl = CreateWindow(TEXT("button"), TEXT("Apply interval")
  , WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_MULTILINE, 160, 200, 120, 30
  , hwnd, (HMENU)(OBJ_ID105), ((LPCREATESTRUCT)lParam)->hInstance, NULL);
 Stop_update = CreateWindow(TEXT("button"), TEXT("STOP")
  , WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_MULTILINE, 290, 200, 80, 30
  , hwnd, (HMENU)(OBJ_ID106), ((LPCREATESTRUCT)lParam)->hInstance, NULL);
 log_init();
 update_sensor_list();
 return 0;

case WM_TIMER:
 switch (wParam)
 {
 case ID_TIMER1:
  get_sensor_values(selected_sensor_index);
  display_sensor_values(Sensor_live_data);
  log_location_data();
  break;
 }
 return 0;

case WM_COMMAND:
 if (LOWORD(wParam) == OBJ_ID104 && HIWORD(wParam) == CBN_SELCHANGE)
 {
  selected_sensor_index = SendMessageA(ComboBox_Sensorlist, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
  if (selected_sensor_index == 0) { selected_sensor_index = -1; KillTimer(GNSS_Setup_Window, ID_TIMER1); }
  else selected_sensor_index -= 1;
  if (selected_sensor_index > -1)
  {
   get_sensor_values(selected_sensor_index);
   display_sensor_values(Sensor_live_data);
  }   
 }
 switch (LOWORD(wParam))
 {/*Processing commands*/;
 case OBJ_ID105:apply_sensor_update_interval();
  break;
 case OBJ_ID106:KillTimer(GNSS_Setup_Window, ID_TIMER1);
  break;
 }
 return 0;

case WM_SIZE:
 return 0;

case WM_PAINT:
 hdc = BeginPaint(hwnd, &ps);
 EndPaint(hwnd, &ps);
 return 0;

case WM_CLOSE:
 Main_Close();
 DestroyWindow(hwnd);
 return 0;

case WM_DESTROY:
 PostQuitMessage(0);
 return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}

void ShowMessage(LPCTSTR uzenet, LPCTSTR cim, HWND kuldo)
{
MessageBox(kuldo, uzenet, cim, MB_OK);
}

//Segédfüggvények

//Ütemező leállítása
void Main_Close(void)
{
KillTimer(GNSS_Setup_Window, ID_TIMER1);
release_GNSS();
}

//Szenzorok lekérdezése
void update_sensor_list(void)
{
int i;
SendMessageA(ComboBox_Sensorlist, CB_RESETCONTENT, 0, 0);
SendMessageA(ComboBox_Sensorlist, CB_ADDSTRING, 0, (LPARAM)"Select a GNSS sensor");
for (i = 0; i < sensor_current_count; ++i)
{
 SendMessageA(ComboBox_Sensorlist, CB_ADDSTRING, 0, (LPARAM)szenzorinfok[i].sensor_name);
}
SendMessageA(ComboBox_Sensorlist, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
}

//Ütemező indítása és leállítása
void apply_sensor_update_interval(void)
{
if (selected_sensor_index == -1) return;
char szoveg[16];
int upd_interval;
GetWindowTextA(Sensor_upd_intvl, szoveg, GetWindowTextLengthA(Sensor_upd_intvl) + 1);
upd_interval = atoi(szoveg);
if (upd_interval < 100) upd_interval = 100;
if (sensor_update_active == 1) KillTimer(GNSS_Setup_Window, ID_TIMER1);
else sensor_update_active = 1;
SetTimer(GNSS_Setup_Window, ID_TIMER1, upd_interval, (TIMERPROC)NULL);
}



5 Helyadatok elérése böngészőből (JavaScript)

Egyszerűsége és könnyű hozzáférhetősége miatt nem megyek el szó nélkül a JavaScript beépített geolocation API könyvtára mellett. Nagyon minimális erőfeszítéssel hozzáférhetünk a helyadatokhoz az ún. navigator objektumok felhasználásával.

A két legfontosabb metódus:
• getCurrentPositions(): a helyadatok egyszeri lekérdezése.
• watchPosition(): a helyadatok automatikus lekérdezése érzékelhető helyváltoztatás esetén. Leállítani a clearWatch() metódussal lehet.

Mindkét metódus paraméterként egy callback metódusként használt függvényt vár paraméterként, ami szintén rendelkezik egy paraméterrel.
Ezen keresztül férhetünk hozzá a helyadatokhoz:
• coords.latitude
• coords.longitude
• coords.accuracy
• coords.altitude
• coords.altitudeAccuracy
• coords.heading
• coords.speed
• timestamp.

Megjegyzem, hogy a helyadatok lekérdezése történhet időzítővel a setInterval() JavaScript metódusával. Ilyenkor megszabhatjuk a frissítés gyakoriságát is.


<!DOCTYPE html>
<html>
<body>

<p>Helyadatok lekérése böngészőben</p>
<p id="adatok">Helyadatok lekérése böngészőben</p>

<script>
var x = document.getElementById("adatok");

if (navigator.geolocation) {
 navigator.geolocation.watchPosition(showPosition);
} else {
 x.innerHTML = "A böngésző nem támogatja a helylekérdezést.";
}

function showPosition(position) {
 x.innerHTML = "Latitude: " + position.coords.latitude +
 "<br>Longitude: " + position.coords.longitude;
}
</script>

</body>
</html>


Működés közben:


KAPCSOLAT

E-mail:
feher.konyvek@gmail.com
KAPCSOLAT

E-mail:
feher.konyvek@gmail.com
Vissza a tartalomhoz