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: