Gnss Driver Interface Adaptation

1. GNSS Driver Framework Introduction

The location service component is used to determine where the user's device is, using latitude and longitude to represent the device's location. OpenHarmony uses multiple positioning technologies to provide location services, such as GNSS positioning, base station positioning, WLAN/Bluetooth positioning (base station positioning and WLAN/Bluetooth positioning are collectively referred to as "network positioning technology").

1.1 Source Code Framework Introduction

/base/location/location      # Source code directory structure:
  ├── figures       # Store architecture diagrams in readme
  ├── frameworks    # Framework code
  ├── interfaces    # External interfaces 
  ├── sa_profile    # SA configuration files
  ├── services      # Location service SA code directory
  ├── test          # Test code directory
device/soc/unisoc/p7885/location/gnss # Driver interface adaptation
  ├── vendorGnssAdapter.cpp # Compiled into vendorGnssAdapter.so
drivers/peripheral/location # HDI interface layer
drivers/interface/location/gnss/v1_0 # IDL interface
device/board/revoview/wukong100\init.uis7885.gnss.cfg # Init configuration file
vendor/revoview/wukong100/hdf_config/uhdf # HCS configuration file
device/soc/unisoc/p7885/hardware/location/lib64/libgnssmgt.so # Closed source library

HDF GNSS Framework Overall Diagram

GNSS Framework Overall Diagram Description:

  • NAPI component is a set of external interfaces based on the Node.js N-API specification for native module extension development framework
  • C++ SDK is mainly used for server-side C++ applications, such as background services for C++ applications
  • All functional APIs related to basic positioning capabilities are provided through Locator (where input parameters need to provide the current application's AbilityInfo information for system management of application positioning requests)
  • All functional APIs related to (reverse) geocoding conversion capabilities are provided through GeoConvert

2. NAPI Usage Instructions

2.1 NAPI Interface Description

Table 1 Location Information API Table

Interface Name Function Description
on(type: 'locationChange', request: LocationRequest, callback: Callback<Location>) : void Enable location change subscription and initiate location request.
off(type: 'locationChange', callback?: Callback<Location>) : void Disable location change subscription and delete corresponding location request.
on(type: 'locationServiceState', callback: Callback<boolean>) : void Subscribe to location service status changes.
off(type: 'locationServiceState', callback: Callback<boolean>) : void Unsubscribe from location service status changes.
on(type: 'cachedGnssLocationsReporting', 
request: CachedGnssLocationsRequest, callback: Callback<Array<Location>>) : void;
Subscribe to cached GNSS location reporting.
off(type: 'cachedGnssLocationsReporting', callback?: Callback<Array<Location>>) : void; Unsubscribe from cached GNSS location reporting.
on(type: 'gnssStatusChange', callback: Callback<SatelliteStatusInfo>) : void; Subscribe to satellite status information update events.
off(type: 'gnssStatusChange', callback?: Callback<SatelliteStatusInfo>) : void; Unsubscribe from satellite status information update events.
on(type: 'nmeaMessageChange', callback: Callback<string>) : void; Subscribe to GNSS NMEA information reporting.
off(type: 'nmeaMessageChange', callback?: Callback<string>) : void; Unsubscribe from GNSS NMEA information reporting.
on(type: 'fenceStatusChange', request: GeofenceRequest, want: WantAgent) : void; Add geofence and subscribe to geofence event reporting.
off(type: 'fenceStatusChange', request: GeofenceRequest, want: WantAgent) : void; Delete geofence and unsubscribe from geofence events.
getCurrentLocation(request: CurrentLocationRequest, callback: AsyncCallback<Location>) : void Get current location, using callback to return results asynchronously.
getCurrentLocation(request?: CurrentLocationRequest) : Promise<Location> Get current location, using Promise to return results asynchronously.
getLastLocation(callback: AsyncCallback<Location>) : void Get last location, using callback to return results asynchronously.
getLastLocation() : Promise<Location> Get last location, using Promise to return results asynchronously.
isLocationEnabled(callback: AsyncCallback<boolean>) : void Check if location service is enabled, using callback to return results asynchronously.
isLocationEnabled() : Promise<boolean> Check if location service is enabled, using Promise to return results asynchronously.
requestEnableLocation(callback: AsyncCallback<boolean>) : void Request to enable location service, using callback to return results asynchronously.
requestEnableLocation() : Promise<boolean> Request to enable location service, using Promise to return results asynchronously.
enbleLocation(callback: AsyncCallback<boolean>) : void Enable location service, using callback to return results asynchronously.
enableLocation() : Promise<boolean> Enable location service, using Promise to return results asynchronously.
disableLocation(callback: AsyncCallback<boolean>) : void Disable location service, using callback to return results asynchronously.
disableLocation() : Promise<boolean> Disable location service, using Promise to return results asynchronously.
getCachedGnssLocationsSize(callback: AsyncCallback<number>) : void; Get the number of cached GNSS locations, using callback to return results asynchronously.
getCachedGnssLocationsSize() : Promise<number>; Get the number of cached GNSS locations, using Promise to return results asynchronously.
flushCachedGnssLocations(callback: AsyncCallback<boolean>) : void; Get all GNSS cached locations and clear GNSS cache queue, using callback to return results asynchronously.
flushCachedGnssLocations() : Promise<boolean>; Get all GNSS cached locations and clear GNSS cache queue, using Promise to return results asynchronously.
sendCommand(command: LocationCommand, callback: AsyncCallback<boolean>) : void; Send extended commands to location service subsystem, using callback to return results asynchronously.
sendCommand(command: LocationCommand) : Promise<boolean>; Send extended commands to location service subsystem, using Promise to return results asynchronously.
isLocationPrivacyConfirmed(type : LocationPrivacyType, callback: AsyncCallback<boolean>) : void; Query whether user agrees to location service privacy statement, using callback to return results asynchronously.
isLocationPrivacyConfirmed(type : LocationPrivacyType,) : Promise<boolean>; Query whether user agrees to location service privacy statement, using Promise to return results asynchronously.
setLocationPrivacyConfirmStatus(type : LocationPrivacyType, isConfirmed : boolean, 
callback: AsyncCallback<boolean>) : void;
Set and record whether user agrees to location service privacy statement, using callback to return results asynchronously.
setLocationPrivacyConfirmStatus(type : LocationPrivacyType, isConfirmed : boolean) : Promise<boolean>; Set and record whether user agrees to location service privacy statement, using Promise to return results asynchronously.

2.2 Steps for Application Layer to Obtain Device Location Information

2.2.1 Obtain Location Permission

Need to apply for ohos.permission.LOCATION and ohos.permission.LOCATION_IN_BACKGROUND permissions. For details, refer to accesstoken-guidelines.md

2.2.2 Import geolocation Module
import geolocation from '@ohos.geolocation'
2.2.3 Instantiate LocationRequest Object to Inform the System What Type of Location Service to Provide and Location Result Reporting Frequency
  • Method 1

    Provide API usage methods close to usage scenarios for developers

    export enum LocationRequestScenario {
       UNSET = 0x300,
       NAVIGATION,// Navigation scenario
       TRAJECTORY_TRACKING,// Trajectory tracking scenario
       CAR_HAILING,// Car hailing scenario
       DAILY_LIFE_SERVICE,// Daily life service scenario
       NO_POWER,// No power scenario
    }
    

    Taking navigation scenario as an example

    var requestInfo = {
        'scenario':0x301,
        'timeInterval':0,
        'distanceInterval':0,
        'maxAccuracy':0
    };
    
  • Method 2

    Provide location priority strategy API

    export enum LocationRequestPriority {
      UNSET = 0x200,
      ACCURACY,// Location accuracy priority strategy
      LOW_POWER,// Fast location priority strategy
      FIRST_FIX,// Low power location priority strategy
    }
    

    Taking location accuracy priority strategy as an example

    var requestInfo = {
       'priority':0x201,
       'timeInterval':0,
       'distanceInterval':0,
       'maxAccuracy':0
    };
    
2.2.4 Instantiate Callback Object to Provide Location Reporting Path to the System

Applications need to implement the callback interface defined by the system and instantiate it. The system will report the real-time location result of the device through this interface when location is successfully determined.

var locationChange = (location) => {
    console.log('locationChanger:data' + JSON.stringify(location));
}
2.2.5 Start Positioning
geolocation.on('locationChange',requestInfo,locationChange);
2.2.6 End Positioning
geolocation.on('locationChange',locationChange);
2.2.7 Get Last Historical Location (Optional)
geolocation.getLastLocation((data) => {
    console.log('locationChanger:data' + JSON.stringify(location)); 
}
)

2.3 Steps for Application Layer to Perform Coordinate and Geocoding Conversion

2.3.1 Import geolocation Module
import geolocation from '@ohos.geolocation'
2.3.2 Convert Coordinates to Geographic Location
var reverseGeocodeRequest = {"latitude": 31.12, "longitude": 121.11, "maxItems": 1};
geolocation.getAddressesFromLocation(reverseGeocodeRequest, (data) => {
   console.log('getAddressesFromLocation: ' + JSON.stringify(data));
});
2.3.3 Convert Location Description to Coordinates
var geocodeRequest = {"description": "上海市浦东新区xx路xx号", "maxItems": 1};
geolocation.getAddressesFromLocationName(geocodeRequest, (data) => {
   console.log('getAddressesFromLocationName: ' + JSON.stringify(data));
});

2. GNSS Framework HDI Interface Adaptation Description in OH:

The HDI interface of GNSS corresponds one-to-one logically with the GNSS native driver interface (Linux or Android driver provided by the manufacturer), but specific parameters and function names need to be converted and mapped.

Four HDI interface functions: EnableGnss, DisableGnss, StartGnss, StopGnss

Four GNSS native driver interface functions: gnss_enable, gnss_disable, gnss_start, gnss_stop

In vendorGnssAdapter.cpp, convert and encapsulate the parameters of native driver interface functions into HDI interface functions, then compile them into so files for HDI layer to call.

3. Prerequisites for Adapting OH GNSS Framework

  • Closed source GNSS driver provided by the manufacturer (e.g., libgnssmgt.so)

  • Test whether native GNSS is working properly. Switch current user to location_host, modify /etc/passwd:

    base/startup/init/services/etc/group:location_host:x:1022:
    base/startup/init/services/etc/passwd:loation_host:x:1022:1022:::/bin/false
    

4. GNSS Adaptation Process

4.1 Configuration File Modification

vendor/XXX/XXX/hdf_config/uhdf/device_info.hcs

location :: host {
    hostName = "location_host";
    priority = 50;
    uid = "location_host";
    gid = ["location_host"];
    location_gnss_device :: device {
        device0 :: deviceNode {
            policy = 2;
            priority = 100;
            preload = 2;
            moduleName = "liblocation_gnss_hdi_driver.z.so";
            serviceName = "gnss_interface_service";
        }
    }
    location_agnss_device :: device {
        device0 :: deviceNode {
            policy = 2;
            priority = 100;
            preload = 2;
            moduleName = "liblocation_agnss_hdi_driver.z.so";
            serviceName = "agnss_interface_service";
        }
    }
    location_geofence_device :: device {
        device0 :: deviceNode {
            policy = 2;
            priority = 100;
            preload = 2;
            moduleName = "liblocation_geofence_hdi_driver.z.so";
            serviceName = "geofence_interface_service";
        }
    }
}

4.2 Modify GNSS Node Permissions

The GNSS driver may need to read and write configuration files, device files, or system status during operation. The corresponding files need to be changed to owner location_host. File permissions are automatically modified at each boot. /vendor/etc/init.product_name.cfg

"name":"boot", "cmds":[
..........................,// Add the following fields, modify names according to actual file names
chown location_host location_host /dev/gnss0,
chmod 660 /dev/gnss0,
chwon location_host location_host ..., 
chmod 660 ....
]

For example, init.xxx.gnss.cfg

4.3 Compile vendorGnssAdapter.so

Place source files vendorGnssAdapter.cpp and vendorGnssAdapter.h in device/board/company_name/${device_name}/gnss directory. In vendorGnssAdapter.cpp, convert and encapsulate the parameters of native driver interface functions into HDI interface functions.

#define GNSSMGT "/vendor/soc_platform/lib64/libgnssmgt.z.so"
...
int gnss_enable(GnssCallbackStruct *callbacks) {
  LBSLOGE(GNSS, "%{public}s entered", GNSSMGT);
  if (callbacks == nullptr){
    LBSLOGE(GNSS, "%{public}s callbacks == nullptr return", GNSSMGT);
  }
  DL_RET ret=SO_OK;
  g_GCS_ = *callbacks;
  g_Handle = dlopen(GNSSMGT, RTLD_LAZY);
  LBSLOGE(GNSS, "%{public}s GNSSMGT handle addr is %x", GNSSMGT, g_Handle);
  if (g_Handle == NULL) 
  {
    LBSLOGE(GNSS, "%{public}s load failed", GNSSMGT);
    return LOAD_NOK;
  }
  gps_init = (pGnssmgt_init)dlsym(g_Handle, "gnssmgt_init");
  LBSLOGE(GNSS, "%{public}s gps_init addr is %{public}x", GNSSMGT, gps_init);
  gps_start = (pGnssmgt_start)dlsym(g_Handle, "gnssmgt_start");
  LBSLOGE(GNSS, "%{public}s gps_start addr is %{public}x", GNSSMGT, gps_start);
  gps_stop = (pGnssmgt_stop)dlsym(g_Handle, "gnssmgt_stop");
  LBSLOGE(GNSS, "%{public}s gps_stop addr is %{public}x", GNSSMGT, gps_stop);
  gps_cleanup = (pGnssmgt_cleanup)dlsym(g_Handle, "gnssmgt_cleanup");
  LBSLOGE(GNSS, "%{public}s gps_cleanup addr is %{public}x", GNSSMGT, gps_cleanup);
  ...
  gps_init(&sGpsCallbacks);
  return ret;
}

Modify ohos.build, add dependent so modules and source code modules

{
    "subsystem": "subsystem_name",
    "parts": {
        "component_name": {
        "module_list": [
.....
        "//device/board/company_name/${device_name}/gnss:vendorGnssAdapter",
.....
            ]
        }
    }
}

Write BUILD.gn, configure specific paths and source code for dependent modules

import("//build/ohos.gni")
import("//vendor/$product_company/$product_name/product.gni")
ohos_shared_library("vendorGnssAdapter") {
    output_name = "vendorGnssAdapter"
    cflags = [
        "-w",
        "-g",
        "-O",
        "-fPIC",
    ]
defines += [
    "__USER__"
]
include_dirs = [
    "//drivers/peripheral/location/gnss/hdi_service",
    "//base/location/interfaces/inner_api/include",
]
sources = [
    "vendorGnssAdapter.cpp",
]
deps = [
]
external_deps = [
    "hiviewdfx_hilog_native:libhilog",
]
install_images = [ chipset_base_dir ]
part_name = "component_name"
subsystem_name = "subsystem_name"
install_enable = true
output_prefix_override = true
output_extension = "so"
}

4.4 HDI Layer Loads vendorGnssAdapter.so

  const std::string VENDOR_NAME = "vendorGnssAdapter.so";// Vendor driver
  void LocationVendorInterface::Init()// Initialize and load driver
  {
      ...
      vendorHandle_ = dlopen(VENDOR_NAME.c_str(), RTLD_LAZY);
      ...
      GnssVendorDevice *gnssDevice = static_cast<GnssVendorDevice *>(dlsym(vendorHandle_, "GnssVendorInterface"));
      ...
      vendorInterface_ = gnssDevice->get_gnss_interface();
      ...
  }

5. Testing and Verification

5.1 Compilation

./build.sh --product-name yangfan --ccache -T LocatorFuzzTest
./build.sh --product-name yangfan --ccache -T gnss_test
./build.sh --product-name yangfan --ccache -T LocatorServiceAbilityTest

5.2 Driver Testing

hdc file send gnss_test /data/
hdc shell
cd /data
chmod 777 gnss_test 
./gnss_test

5.3 Service Testing

hdc file send LocatorServiceAbilityTest /data/
hdc shell
cd /data
chmod 777 LocatorServiceAbilityTest 
./LocatorServiceAbilityTest

View log

5.4 Location App Testing

hdc app install -r Location.hap

base_location