⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 geozone.c

📁 Open DMT Client C Source code
💻 C
📖 第 1 页 / 共 2 页
字号:
// ----------------------------------------------------------------------------// Copyright 2006-2007, Martin D. Flynn// All rights reserved// ----------------------------------------------------------------------------//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// // http://www.apache.org/licenses/LICENSE-2.0// // Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//// ----------------------------------------------------------------------------// Description://  GPS rule module for checking for GeoZone arrival/departure// ---// Change History://  2006/05/07  Martin D. Flynn//     -Initial release//  2007/01/28  Martin D. Flynn//     -WindowsCE port//     -Receiving a 'GEOF_CMD_REMOVE' with no specific zone-id will remove//      ALL existing geozones.  This is used for purposes of reloading the//      entire geozone cache.//     -Qualify 'GEOZONE_FILENAME' location to directory specified by the//      'CONFIG_DIR' definition provided in 'defaults.h'//  2007/04/28  Martin D. Flynn//     -Changed to 'back-date' arrival/departure point to actual point of //      arrival/departure.// ----------------------------------------------------------------------------#include "stdafx.h" // TARGET_WINCE#include "custom/defaults.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "custom/startup.h"#include "custom/log.h"#include "tools/stdtypes.h"#include "tools/gpstools.h"#include "tools/strtools.h"#include "tools/utctools.h"#include "tools/io.h"#include "base/propman.h"#include "base/statcode.h"#include "base/events.h"#include "modules/geozone.h"// ----------------------------------------------------------------------------#define ARRIVE_PRIORITY             PRIORITY_NORMAL#define DEPART_PRIORITY             PRIORITY_NORMAL// ----------------------------------------------------------------------------// where the geozone table will be saved#define GEOZONE_FILENAME            (CONFIG_DIR_ "GEOZONE.DAT")// ----------------------------------------------------------------------------// pre-allocate the maximum number of possible geozones#ifndef MAX_GEOZONES  // <-- a different value could be specified in 'defaults.h'#  define MAX_GEOZONES              4000       // 80K bytes (@20 bytes/rcd)#endif// define to force all inserted ZoneIDs to be unique//#define FORCE_UNIQUE_ZONE_IDS// any ZoneID, other than 'NO_ZONE', is valid#define IS_VALID_ZONE(Z)            ((Z) != NO_ZONE)// true if arrival/departure should be set-back to actual arrival/departure point#define SETBACK_POINT               (utTrue)// ----------------------------------------------------------------------------// This value represents the length of the data presented in the 'Add GeoZone' command#define PACKED_GEOZONE_SIZE         (14 + sizeof(GeoZoneID_t))// ----------------------------------------------------------------------------#ifdef PROTOCOL_THREAD#include "tools/threads.h"static threadMutex_t                geozMutex;#define GEOZ_LOCK                   MUTEX_LOCK(&geozMutex);#define GEOZ_UNLOCK                 MUTEX_UNLOCK(&geozMutex);#else#define GEOZ_LOCK#define GEOZ_UNLOCK#endif// ----------------------------------------------------------------------------static utBool           didInitialize   = utFalse;static GeoZone_t        geoZoneList[MAX_GEOZONES];static UInt16           maxZones        = MAX_GEOZONES;static UInt16           usedZones       = 0;static utBool           geozIsDirty     = utFalse;static GPS_t            arrivePoint; // need initializationstatic GPS_t            departPoint; // need initializationstatic eventAddFtn_t    ftnQueueEvent   = 0;// ----------------------------------------------------------------------------/* add a geofence event to the event queue */static void _queueGeofenceEvent(PacketPriority_t priority, StatusCode_t code, const GPS_t *gps, int geofID){    if (gps && ftnQueueEvent) {        Event_t evRcd;        evSetEventDefaults(&evRcd, code, 0L, gps);        evRcd.geofenceID[0] = geofID;        (*ftnQueueEvent)(priority, DEFAULT_EVENT_FORMAT, &evRcd);    }}// ----------------------------------------------------------------------------void geozSetVersion(const char *v){    propSetString(PROP_GEOF_VERSION, v);}const char *geozGetVersion(){    return propGetString(PROP_GEOF_VERSION, "");}// ----------------------------------------------------------------------------/* check new GPS fix for various motion events */void geozCheckGPS(const GPS_t *oldFix, const GPS_t *newFix){        /* new fix required */    if (!newFix) {        //logDEBUG(LOGSRC,"No new fix! ...");        return;    }    /* in GeoZone? */    //logDEBUG(LOGSRC,"Zone checking in progress ...");    GeoZone_t *inZone = geozInZone(&(newFix->point));    //if (isDebugMode() && inZone) { logDEBUG(LOGSRC,"!!!!!! In Zone %d", inZone->zoneID); }        /* get zones */    GeoZoneID_t curZoneID = geozGetCurrentID();    GeoZoneID_t newZoneID = inZone? inZone->zoneID : NO_ZONE;        /* GeoZone changed? */    // This zone-change-checking method only triggers an arrival/departure if    // we're moving from inside the CURRENT zone to outside ALL zones,    // or from outside ALL zones to inside ANY zone.    // This allows creating unique ZoneIDs for overlapping sub-zones, and the     // Arrival event will then indicate which specific sub-zone was entered.    utBool zoneChange = (IS_VALID_ZONE(curZoneID) != IS_VALID_ZONE(newZoneID))? utTrue : utFalse;    // This zon-change-checking method only triggers an arrival/departure if    // were moving from inside the CURRENT zone to outside the CURRENT zone,    // or from outside ALL zones to inside ANY zone.    // All overlapping sub-zones should have the same ZoneID.    //utBool zoneChange = (curZoneID != newZoneID);        /* check zone change */    if (zoneChange) {        // My 'Zone' state has changed        //logDEBUG(LOGSRC,"GeoZone state changed: %u != %u", curZoneID, newZoneID);                /* check departure */        if (IS_VALID_ZONE(curZoneID)) {            // I was in 'curZoneID', but now I am not (ie. departing 'curZoneID')            if (!gpsIsValid(&departPoint)) {                // This is the first 'departure' event                gpsCopy(&departPoint, newFix); // a valid 'fixtime' is assumed            }            // check 'departure' delay            UInt16 depDelay = (UInt16)propGetUInt32(PROP_GEOF_DEPART_DELAY, 0L);            if ((depDelay == 0) || ((departPoint.fixtime + (UInt32)depDelay) <= utcGetTimeSec())) {                // I've now departed the zone                const GPS_t *departFix = SETBACK_POINT? &departPoint : newFix;                _queueGeofenceEvent(DEPART_PRIORITY, STATUS_GEOFENCE_DEPART, departFix, curZoneID);                geozSetCurrentID(NO_ZONE);                gpsClear(&departPoint);                logINFO(LOGSRC,"Departed %u [%u]\n", curZoneID, geozGetCurrentID());                startupSaveProperties();            } else {                // not yet ready to mark as 'departed'                //logDEBUG(LOGSRC,"Depart in %lu seconds", ((departPoint.fixtime + (UInt32)depDelay) - utcGetTimeSec()));            }        } else {            // I wasn't in any known zone (I'm not departing)            gpsClear(&departPoint);        }                /* check arrival */        if (IS_VALID_ZONE(newZoneID)) {            // I was not in 'newZoneID' before, but now I am (arriving 'newZoneID')            if (!gpsIsValid(&arrivePoint)) {                // This is the first 'arrival' event                gpsCopy(&arrivePoint, newFix); // a valid 'fixtime' is assumed            }            // check 'arrival' delay            UInt16 arrDelay = (UInt16)propGetUInt32(PROP_GEOF_ARRIVE_DELAY, 0L);            if ((arrDelay == 0) || ((arrivePoint.fixtime + (UInt32)arrDelay) <= utcGetTimeSec())) {                // I've now arrived in the zone                const GPS_t *arriveFix = SETBACK_POINT? &arrivePoint : newFix;                geozSetCurrentID(newZoneID);                _queueGeofenceEvent(ARRIVE_PRIORITY, STATUS_GEOFENCE_ARRIVE, arriveFix, newZoneID);                gpsClear(&arrivePoint);                logINFO(LOGSRC,"Arrived %u [%u]\n", newZoneID, geozGetCurrentID());                startupSaveProperties();            } else {                // not yet ready to mark as 'arrived'                //logDEBUG(LOGSRC,"Arrive in %lu seconds", ((arrivePoint.fixtime + (UInt32)arrDelay) - utcGetTimeSec()));            }        } else {            // I'm not arriving at any new zone            gpsClear(&arrivePoint);        }            } else {        // My 'Zone' state has not changed        // (ie. If I'm 'out', I'm still 'out'.  If I'm 'in', I'm still 'in'.)        //logDEBUG(LOGSRC,"GeoZone state NOT changed: %2u / %2u\n", curZoneID, newZoneID);        gpsClear(&departPoint);        gpsClear(&arrivePoint);    }}// ----------------------------------------------------------------------------/* return current geozone id */GeoZoneID_t geozGetCurrentID(){    return (GeoZoneID_t)propGetUInt32(PROP_GEOF_CURRENT, (UInt32)NO_ZONE);}/* set current geozone id */void geozSetCurrentID(GeoZoneID_t zoneID){    propSetUInt32(PROP_GEOF_CURRENT, (UInt32)zoneID);}/* convert GeoZone point to GPS point */static GPSPoint_t *_geozToGPSPoint(GPSPoint_t *gp, const GeoZonePoint_t *gzp){    if (gzp && gp) {        gp->latitude  = gzp->latitude;        gp->longitude = gzp->longitude;        return gp;    } else {        return (GPSPoint_t*)0;    }}/* check new GPS fix for various motion events */static utBool _geozInZone(GeoZone_t *geoz, const GPSPoint_t *newGP){    utBool inZone = utFalse;    if (geoz && newGP && IS_VALID_ZONE(geoz->zoneID)) {                //logDEBUG(LOGSRC,"Target point: %.5lf / %.5lf\n", newGP->latitude, newGP->longitude);        GPSPoint_t geozGP_0, geozGP_1;        double deltaMeters, radiusMeters = (double)geoz->radius;        switch (geoz->type) {#ifdef GEOF_SWEPT_POINT_RADIUS            case GEOF_SWEPT_POINT_RADIUS:                // not supported in this implementation.                // default to dual point/radius below#endif                            case GEOF_DUAL_POINT_RADIUS:                _geozToGPSPoint(&geozGP_0, &(geoz->point[0]));                if (gpsPointIsValid(&geozGP_0)) {                    deltaMeters = gpsMetersToPoint(newGP, &geozGP_0);                    //logDEBUG(LOGSRC,"  Zone %d A (%.5lf / %.5lf) [%.1lf <= %.1lf]", geoz->zoneID, geozGP_0.latitude, geozGP_0.longitude, deltaMeters, radiusMeters);                    if (deltaMeters <= radiusMeters) {                        inZone = utTrue;                        break;                    }                }                _geozToGPSPoint(&geozGP_1, &(geoz->point[1]));                if (gpsPointIsValid(&geozGP_1)) {                    deltaMeters = gpsMetersToPoint(newGP, &geozGP_1);                    //logDEBUG(LOGSRC,"  Zone %d B (%.5lf / %.5lf) [%.1lf <= %.1lf]", geoz->zoneID, geozGP_1.latitude, geozGP_1.longitude, deltaMeters, radiusMeters);                    if (deltaMeters <= radiusMeters) {                        inZone = utTrue;                        break;                    }                }                break;                            case GEOF_BOUNDED_RECT:                // North of the top latitude                if (newGP->latitude > (double)geoz->point[0].latitude) {                     break;                }                // South of the bottom latitude                if (newGP->latitude < (double)geoz->point[1].latitude) {                     break;                }                // West of the left longitude (will fail if zone spans +/- 180 degrees)                if (newGP->longitude < (double)geoz->point[0].longitude) {                     break;                }                // East of the right longitude (will fail if zone spans +/- 180 degrees)                if (newGP->longitude > (double)geoz->point[1].longitude) {                     break;                }                inZone = utTrue;                break;                #ifdef GEOF_DELTA_RECT            case GEOF_DELTA_RECT:                // North of the top latitude                geozGP_0.latitude = (double)(geoz->point[0].latitude + geoz->point[1].latitude); // top                if (newGP->latitude > geozGP_0.latitude) {                     break;                }                // South of the bottom latitude                geozGP_0.latitude = (double)(geoz->point[0].latitude - geoz->point[1].latitude); // bottom                if (newGP->latitude < geozGP_0.latitude) {                     break;                }                // West of the left longitude (will fail if zone spans +/- 180 degrees)                geozGP_0.longitude = (double)(geoz->point[0].longitude - geoz->point[1].longitude); // left                if (newGP->longitude < geozGP_0.longitude) {                     break;                }                // East of the right longitude (will fail if zone spans +/- 180 degrees)                geozGP_0.longitude = (double)(geoz->point[0].longitude + geoz->point[1].longitude); // right                if (newGP->longitude > geozGP_0.longitude) {                     break;                }                inZone = utTrue;                break;#endif        } // switch (geoz->type)            } // if (...)    return inZone;}/* return the zone where the specified point is located */GeoZone_t *geozInZone(const GPSPoint_t *newGP){    /* is newGP inside GeoZone? */    GeoZone_t *gz = (GeoZone_t*)0;    UInt16 i;    GEOZ_LOCK {        for (i = 0; i < usedZones; i++) {            if (_geozInZone(&geoZoneList[i], newGP)) {                gz = &geoZoneList[i];                break;            }        }    } GEOZ_UNLOCK    return gz;}// ----------------------------------------------------------------------------static void _geozClearAll(){    memset(geoZoneList, sizeof(geoZoneList), 0);    geozIsDirty = (usedZones > 0)? utTrue : utFalse;    usedZones = 0;}static GeoZone_t *_geozDecodeGeoZone(Buffer_t *src, GeoZone_t *gz, utBool hiRes){    // this method decodes a GeoZone as presented in the packet.    UInt32      zoneID;    UInt32      typeRadius;    GPSPoint_t  pt0, pt1;    int         fldCnt;    if (hiRes) {        // High resolution point        fldCnt = binBufScanf(src, "%4u%2u%8g%8g", &zoneID, &typeRadius, &pt0, &pt1);    } else {        // Standard resolution point        fldCnt = binBufScanf(src, "%2u%2u%6g%6g", &zoneID, &typeRadius, &pt0, &pt1);    }    memset(gz, 0, sizeof(GeoZone_t));    if (fldCnt == 4) {        gz->zoneID = (GeoZoneID_t)zoneID;        gz->type   = (typeRadius >> 13) & 0x7;        gz->radius = typeRadius & 0x1FFF;        gz->point[0].latitude  = (float)pt0.latitude;        gz->point[0].longitude = (float)pt0.longitude;        gz->point[1].latitude  = (float)pt1.latitude;        gz->point[1].longitude = (float)pt1.longitude;        return gz;    } else {        return (GeoZone_t*)0;    }}#ifdef GEOZ_INCL_PRINT_GEOZONEstatic void _geozPrintGeoZone(GeoZone_t *gz){    if (gz) {        logDEBUG(LOGSRC,"GeoZone: %u (typ=%u, rad=%u) 0=%.4f/%.4f, 1=%.4f/%.4f\n",             gz->zoneID, gz->type, gz->radius,             gz->point[0].latitude, gz->point[0].longitude,             gz->point[1].latitude, gz->point[1].longitude);    }}#endif// ----------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -