added files for 2016 workshop

This commit is contained in:
Alexander Schlenk 2016-07-03 23:18:54 +02:00
parent 21d0d1d975
commit 48be875ed8
83 changed files with 12944 additions and 0 deletions

1
2016/android/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.idea

9
2016/android/Geofence/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
.gradle
.idea
*.iml
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures

2
2016/android/Geofence/app/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build
src/main/gen

View File

@ -0,0 +1,37 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 17
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "esrlabs.com.geofence"
minSdkVersion 17
targetSdkVersion 17
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
testOptions {
unitTests.returnDefaultValues = true
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
testCompile('org.robolectric:robolectric:3.0-rc2') {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: 'org.apache.httpcomponents', module: 'httpclient'
}
testCompile 'org.mockito:mockito-core:1.9.5'
testCompile 'org.hamcrest:hamcrest-library:1.3'
compile project(':headunitinterface')
}

View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/andreibechet/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="esrlabs.com.geofence" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<service
android:name="com.esrlabs.geofence.GeofenceApp"
android:enabled="true"
android:exported="true" >
</service>
</application>
</manifest>

View File

@ -0,0 +1,19 @@
package com.esrlabs.geofence;
import android.location.Location;
public class CircleGeofence implements Geofence {
final Location center;
final float radiusInMeters;
public CircleGeofence(Location center, float radiusInMeters) {
this.center = center;
this.radiusInMeters = radiusInMeters;
}
@Override
public boolean containsLocation(Location location) {
return false;
}
}

View File

@ -0,0 +1,8 @@
package com.esrlabs.geofence;
import android.location.Location;
public interface Geofence {
public boolean containsLocation(Location location);
}

View File

@ -0,0 +1,87 @@
package com.esrlabs.geofence;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.esrlabs.headunitinterface.HeadUnit;
import java.util.List;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static com.esrlabs.geofence.Utils.location;
/**
* Steps:
* - register to the location provider
* - connect to the HeadUnitService
* - build geofence object
* - implement the exercise logic (when the user is outside of the geofence show popup; hide it otherwise)
*
* See:
* - that tests are green
* - that the notification appears in the emulator
*/
public class GeofenceApp extends Service implements LocationListener {
public static final String TAG = "GeofenceApp";
private LocationManager locationManager;
private Geofence geofence;
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
if (locationManager == null) {
locationManager = (LocationManager)
this.getSystemService(Context.LOCATION_SERVICE);
}
initLocationListener();
initHeadUnitService();
if (geofence == null) {
final int someRadiusInMeters = 25;
final Location someCenterForTheGeofence = location(NETWORK_PROVIDER, 48.118920, 11.601057);
geofence = new CircleGeofence(someCenterForTheGeofence, someRadiusInMeters);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onLocationChanged(Location location) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}

View File

@ -0,0 +1,34 @@
package com.esrlabs.geofence;
import android.location.Location;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PolygonGeofence implements Geofence {
final List<Location> polygonPoints;
public PolygonGeofence(Location... locations) {
polygonPoints = new ArrayList<Location>(Arrays.asList(locations));
}
/**
* It implements the Ray casting algorithm, with the convention that the line is horizontal and
* goes from left to right.
* @param location The point to be checked if is inside the defined polygon shaped geofence
* @return True if the location is inside the defined polygon.
*/
@Override
public boolean containsLocation(Location location) {
int numberOfCorners = polygonPoints.size();
//adding the first corner at the end so that we can count the edge between last and first corners too
List<Location> corners = new ArrayList<Location>(polygonPoints);
corners.add(polygonPoints.get(0));
return false;
}
}

View File

@ -0,0 +1,14 @@
package com.esrlabs.geofence;
import android.location.Location;
public class Utils {
public static Location location(String provider, double latitude, double longitude) {
Location location = new Location(provider);
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setTime(System.currentTimeMillis());
return location;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -0,0 +1,6 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View File

@ -0,0 +1,5 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">Geofence</string>
</resources>

View File

@ -0,0 +1,5 @@
<resources>
<!-- Base application theme. -->
</resources>

View File

@ -0,0 +1,40 @@
package com.esrlabs.geofence;
import android.location.Location;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
import esrlabs.com.geofence.BuildConfig;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static com.esrlabs.geofence.Utils.location;
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, emulateSdk = 17)
public class CircleGeofenceTest extends TestCase {
public static final double distanceSmallerThanRadiusInDeg = 0.0001;
public static final double distanceLargerThanRadiusInDeg = 0.001;
private static final float someRadiusInMeters = 100;
private static final Location someCenterForTheGeofence = location(NETWORK_PROVIDER, 48.118920, 11.601057);
public static final CircleGeofence someCircleGeofence = new CircleGeofence(someCenterForTheGeofence, someRadiusInMeters);
@Test
public void testContainsLocation() throws Exception {
assertTrue(someCircleGeofence.containsLocation(someLocationInside()));
assertFalse(someCircleGeofence.containsLocation(someLocationOutside()));
}
private Location someLocationInside() {
return location(NETWORK_PROVIDER, someCenterForTheGeofence.getLatitude() + distanceSmallerThanRadiusInDeg, someCenterForTheGeofence.getLongitude());
}
private Location someLocationOutside() {
return location(NETWORK_PROVIDER, someCenterForTheGeofence.getLatitude() + distanceLargerThanRadiusInDeg, someCenterForTheGeofence.getLongitude());
}
}

View File

@ -0,0 +1,114 @@
package com.esrlabs.geofence;
import android.content.ComponentName;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.IBinder;
import android.os.RemoteException;
import com.esrlabs.headunitinterface.HeadUnit;
import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLocationManager;
import java.util.concurrent.atomic.AtomicBoolean;
import esrlabs.com.geofence.BuildConfig;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static com.esrlabs.geofence.CircleGeofenceTest.someCircleGeofence;
import static com.esrlabs.geofence.Utils.location;
import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, emulateSdk = 17)
public class GeofenceAppTest extends TestCase {
private final LocationManager locationManager = (LocationManager)
RuntimeEnvironment.application.getSystemService(Context.LOCATION_SERVICE);
private final ShadowLocationManager shadowLocationManager = shadowOf(locationManager);
private final Location someLocation = Utils.location(NETWORK_PROVIDER, 12.0, 20.0);
private final AtomicBoolean notificationVisibility = new AtomicBoolean(false);
private GeofenceApp geofenceApp;
@Before
public void setUp() throws Exception {
initHeadUnitServiceMock();
setupGeofenceApp();
}
private void initHeadUnitServiceMock() {
IBinder headUnitStub = newTestHeadUnitServerBinder();
shadowOf(RuntimeEnvironment.application).setComponentNameAndServiceForBindService(
new ComponentName("com.esrlabs.headunitinterface", "HeadUnit"), headUnitStub);
}
private IBinder newTestHeadUnitServerBinder() {
return new HeadUnit.Stub() {
@Override
public void showNotification(String text) throws RemoteException {
notificationVisibility.set(true);
}
@Override
public void hideAllNotifications() throws RemoteException {
notificationVisibility.set(false);
}
};
}
private void setupGeofenceApp() {
GeofenceApp service = new GeofenceApp(locationManager, someCircleGeofence);
service.onCreate();
geofenceApp = service;
}
@After
public void tearDown() throws Exception {
geofenceApp.onDestroy();
}
@Test
public void shouldReceiveTheLatestLocation() throws Exception {
simulateNewLocation(someLocation);
assertTrue(someLocation.equals(geofenceApp.latestLocation()));
}
@Test
public void shouldShowPopupWhenTheCurrentLocationIsOutsideTheGeofence() throws Exception {
Location locationInside = location(NETWORK_PROVIDER, someCircleGeofence.center.getLatitude() + CircleGeofenceTest.distanceSmallerThanRadiusInDeg,
someCircleGeofence.center.getLongitude());
simulateNewLocation(locationInside);
assertTrue(locationInside.equals(geofenceApp.latestLocation()));
assertFalse(notificationVisibility.get());
Location locationOutside = location(NETWORK_PROVIDER, someCircleGeofence.center.getLatitude() + CircleGeofenceTest.distanceLargerThanRadiusInDeg,
someCircleGeofence.center.getLongitude());
simulateNewLocation(locationOutside);
assertTrue(locationOutside.equals(geofenceApp.latestLocation()));
assertTrue(notificationVisibility.get());
Location nextLocationInside = location(NETWORK_PROVIDER, someCircleGeofence.center.getLatitude() + CircleGeofenceTest.distanceSmallerThanRadiusInDeg,
someCircleGeofence.center.getLongitude());
simulateNewLocation(nextLocationInside);
assertTrue(nextLocationInside.equals(geofenceApp.latestLocation()));
assertFalse(notificationVisibility.get());
}
private void simulateNewLocation(Location someLocation) {
shadowLocationManager.simulateLocation(someLocation);
}
}

View File

@ -0,0 +1,22 @@
package com.esrlabs.geofence;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class HeadUnitServiceMock extends Service {
public static final String TAG = "HeadUnitServiceMockTest";
final IBinder headUnitStub;
public HeadUnitServiceMock(IBinder headUnitStub) {
this.headUnitStub = headUnitStub;
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return headUnitStub;
}
}

View File

@ -0,0 +1,44 @@
package com.esrlabs.geofence;
import android.location.Location;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
import esrlabs.com.geofence.BuildConfig;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static com.esrlabs.geofence.CircleGeofenceTest.distanceLargerThanRadiusInDeg;
import static com.esrlabs.geofence.Utils.location;
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, emulateSdk = 17)
public class PolygonGeofenceTest extends TestCase {
// Test polygon defined physically like:
// 48.119033, 11.601664 48.119051, 11.601766
// 48.117726, 11.602404 48.117758, 11.602543
public static final Location testPolygonTopRightCorner = location(NETWORK_PROVIDER, 48.119033, 11.601664);
public static final Location testPolygonTopLeftCorner = location(NETWORK_PROVIDER, 48.119051, 11.601966);
public static final Location testPolygonBottomRightCorner = location(NETWORK_PROVIDER, 48.116726, 11.602404);
public static final Location testPolygonBottomLeftCorner = location(NETWORK_PROVIDER, 48.116758, 11.602743);
public static final PolygonGeofence testGeofence = new PolygonGeofence(testPolygonTopRightCorner, testPolygonTopLeftCorner,
testPolygonBottomRightCorner, testPolygonBottomLeftCorner);
@Test
public void testContainsLocation() throws Exception {
assertTrue(testGeofence.containsLocation(someLocationInside()));
assertFalse(testGeofence.containsLocation(someLocationOutside()));
}
private Location someLocationInside() {
return location(NETWORK_PROVIDER, testPolygonTopRightCorner.getLatitude() - 0.001, testPolygonTopRightCorner.getLongitude() - 0.001);
}
private Location someLocationOutside() {
return location(NETWORK_PROVIDER, testPolygonTopRightCorner.getLatitude() + distanceLargerThanRadiusInDeg, testPolygonTopRightCorner.getLongitude());
}
}

View File

@ -0,0 +1,22 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter {
jcenter()
//url "http://jcenter.bintray.com/"
}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}

View File

@ -0,0 +1,18 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Sun Jul 03 23:08:01 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip

164
2016/android/Geofence/gradlew vendored Normal file
View File

@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
2016/android/Geofence/gradlew.bat vendored Normal file
View File

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,23 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 17
buildToolsVersion "22.0.1"
defaultConfig {
minSdkVersion 17
targetSdkVersion 17
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/flo/android-sdks/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,13 @@
package com.esrlabs.headunitinterface;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.esrlabs.headunitinterface">
<application android:allowBackup="true" android:label="@string/app_name">
</application>
</manifest>

View File

@ -0,0 +1,9 @@
// HeadUnit.aidl
package com.esrlabs.headunitinterface;
interface HeadUnit {
void showNotification(String text);
void hideAllNotifications();
}

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">HeadUnitInterface</string>
</resources>

View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,27 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId 'com.esrlabs.headunitservice'
minSdkVersion 17
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
compile project(':headunitinterface')
}

View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/flo/android-sdks/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,13 @@
package com.esrlabs.headunitservice;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.esrlabs.headunitservice" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<service
android:name=".HeadUnitService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.esrlabs.headunitinterface.HeadUnit" />
</intent-filter>
</service>
</application>
</manifest>

View File

@ -0,0 +1,52 @@
package com.esrlabs.headunitservice;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.esrlabs.headunitinterface.HeadUnit;
/**
* A test implementation of the HeadUnit interface
*
* Provides a way to run against the interface without the presence of a real headunit
*
* Will use the Android UI instead
*/
public class HeadUnitService extends Service {
public static final String TAG = "HeadUnitServiceMock";
public HeadUnitService() {
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return binder;
}
private final HeadUnit.Stub binder = new HeadUnit.Stub() {
@Override
public void showNotification(String text) throws RemoteException {
Log.i(TAG, "showNotification '" + text + "'");
Notification.Builder builder = new Notification.Builder(getBaseContext()).setContentText(text).setSmallIcon(R.drawable.tum_logo);
notificationService().notify(0,builder.build());
}
@Override
public void hideAllNotifications() throws RemoteException {
Log.i(TAG, "hideAllNotifications");
notificationService().cancelAll();
}
};
private NotificationManager notificationService() {
return (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">HeadUnitServiceMock</string>
</resources>

View File

@ -0,0 +1,8 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1 @@
include ':app', ':headunitinterface', ':headunitservicemock'

View File

@ -6,3 +6,71 @@ To be able to develop for android and run it in the simulator, you will need the
- latest android sdk
You can find both [here](https://developer.android.com/studio/index.html)
# Display a notification on the headunit
In this task you have to create an android application which will use a geofence and the current location data in order to open/close a popup on the headunit.
## Receive the current location
Use the [android location manager](http://developer.android.com/reference/android/location/LocationManager.html) to request location updates. If the location is retrieved correctly, then the following test will pass.
```java
GeofenceAppTest.shouldReceiveTheLatestLocation()
```
## Bind to a remote service to be able to display notifications
Use the [AIDL](http://developer.android.com/guide/components/aidl.html) to allow interprocess communication between your app and another service which will allow you to display notifications. The AIDL you will use is *HeadUnit.aidl*. You are on the client side. You will need to bind to the service using an intent and a [ServiceConnection](http://developer.android.com/reference/android/content/ServiceConnection.html) object (see [here](http://developer.android.com/guide/components/aidl.html#Expose)).
```java
Intent headUnitServiceIntent = new Intent(HeadUnit.class.getName());
headUnitServiceIntent.setPackage("com.esrlabs.headunitservice");
bindService(headUnitServiceIntent, serviceConnection_object, BIND_AUTO_CREATE);
```
## Implement a circle geofence object to tell if the current is inside a designated area or not
The first step is to implement a circle geofence. You cannot use the google API because that is part of the play API, and it is not supported by our android controller. You have included in the test suite a test class for the circle geofence to help you.
The second step is to display a popup if the current location is outside of a given geofence (alternatively to close if the location is inside). If this is correctly implemented than all the tests should be green (**Note** that unless you are going for the bonus you should disable the test in the *PolygonGeofenceTest* class with *@Ignore* in front of the *@Test*).
For the circle geofence you should use this location as the center and radius of :
(48.262596, 11.668720) and radius of 25 meters
## Observations
In order to ease testing dependancy injection has been used. That means to pass the objects our class will use via a constructor. In android, services are not constructed by the user, instead they are built internally. The needed things for the service to run are instantated during the *onCreate()* call. The constructor in the code is there just for testing purposes. For the functioning of the service you should do the following:
```java
if (locationManager == null) {
locationManager = (LocationManager)
this.getSystemService(Context.LOCATION_SERVICE);
}
```
and
```java
if (geofence == null) {
geofence = myGeofence(...);
}
```
## **Bonus** Implement a polygon geofence instead
You can use the [Ray-casting algorithm](https://en.wikipedia.org/wiki/Point_in_polygon).
#### HINT
Use the slope of a straight line in order to tell if the ray starting from the given point and going in a fixed direction, intersects an edge of the polygon. Take care that *Math.atan()* return radians, and you will have to correct a negative angle:
```java
90 + (90 - Math.abs(angle))
```
For the polygon geofence you should use the following locations as the polygon's cornerns:
(48.262739, 11.668393), (48.262674, 11.668956), (48.262100, 11.668419), (48.262324, 11.670174)

3
2016/ppc/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
gps/UnitTest
.bake
build_UnitTest

1
2016/ppc/.ruby-gemset Normal file
View File

@ -0,0 +1 @@
inga

1
2016/ppc/.ruby-version Normal file
View File

@ -0,0 +1 @@
2.1

View File

@ -10,3 +10,91 @@ To be able to compile your solutions and execute the tests, you will need the fo
see https://esrlabs.github.io/bake/
# GPS on CAN
In this task you will need to receive Can-frames on the can-bus that contain the GPS location of the
vehicle. The raw data has to be converted to arc-milliseconds
1°2'5" == (1*3600+ 2*60 + 5)*1000
**Beware that the system you are running your code on will not support floating point operations.
Use only unsigned and signed integers!**
Still the precision of your calculations has to be +-100 milli-arc-seconds
Dynamic allocation is not supported on the system.
You will have to complete the *GpsConverter.cpp* (and .h).
## Conversion to Arc-Degree
inDegree hex = 180/(2^31-1) * (hex) [°]
#### HINT 1
Try to use constants as much as possible, isntead of computing stuff on the go.
#### HINT 2
In order to aviod losing decimals first multiply with a large factor and then divide to get the result in ms.
## GPS Datalayout in CAN Message
Byte7 ST_LAT_NAVI
Byte6 ST_LAT_NAVI
Byte5 ST_LAT_NAVI
Byte4 ST_LAT_NAVI
Byte3 ST_LONG_NAVI
Byte2 ST_LONG_NAVI
Byte1 ST_LONG_NAVI
Byte0 ST_LONG_NAVI
## Byteorder
Little Endian (Least Significant Byte is at lowest address)
## Status Longitude Navigation
ST_LONG_NAVI
### Possible Values
-180° ... +180°
### Signal type
32 Bit Signed Integer (Byte 0 ... Byte 3)
### Invalid Data
Invalid-Value: 80 00 00 00
Signal not available value: 7F FF FF FF and FF FF FF FF
**Do not forget to check for these values**
## Status Latitude Navigation
ST_LAT_NAVI
### Possible Values
-180° ... +180°
### Signal type
32 Bit Signed Integer (Byte 4 ... Byte 7)
### Invalid Data
Invalid-Value: 80 00 00 00
Signal not available value: 7F FF FF FF and FF FF FF FF
## Send the data over to the AC
Use the *IGpsACPusher*.
## Running the tests
execute `rake run` from this directory

View File

@ -0,0 +1,32 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#ifndef COMMON_TYPES_H
#define COMMON_TYPES_H
/* standard types file to be used for
* all C++ basic software components */
#ifdef UNIT_TEST
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long int uint64;
typedef signed char sint8;
typedef signed short sint16;
typedef signed int sint32;
typedef signed long long int sint64;
#else
#include "Std_Types.h"
typedef volatile uint32 vuint32;
typedef volatile uint32 vuint32_t;
#endif
#endif /* COMMON_TYPES_H */

View File

@ -0,0 +1,92 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#ifndef COMPILETIMECONSTRAINTS_H_
#define COMPILETIMECONSTRAINTS_H_
#include "commonTypes.h"
#define ZGW_JOIN( X, Y ) ZGW_DO_JOIN( X, Y )
#define ZGW_DO_JOIN( X, Y ) ZGW_DO_JOIN2(X,Y)
#define ZGW_DO_JOIN2( X, Y ) X##Y
namespace common
{
template <bool x> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
# define ECU_STATIC_ASSERT( B ) \
typedef char ZGW_JOIN(zgw_static_assert_typedef_, __LINE__) \
[ ::common::STATIC_ASSERTION_FAILURE< (bool)( B ) >::value ]
template<bool Condition>
struct CompileTimeError;
template<>
struct CompileTimeError<false> {};
/**
* STATIC_CHECK will fail when expr evaluates to true
*/
#define STATIC_CHECK(msg, expr) \
{ common::CompileTimeError<(expr)> ERROR_##msg; (void)ERROR_##msg; }
/**
* STATIC_ASSERT will fail when expr evaluates to false
* simple usage: STATIC_ASSERT(too_bad_static_assert_failed, 2 > 3)
*/
#define STATIC_ASSERT(msg, expr) \
{ common::CompileTimeError<!(expr)> ERROR_##msg; (void)ERROR_##msg; }
/**
* another example-setup for compile-time-check: a class only has to inherit from this constraint,
* so the constructor of this Constraint has to be compiled and the static check is executed
* by the compiler.
* will only compile if ACTUAL_SIZE <= ALLOWED_SIZE
*
* the argument passed to the STATIC_CHECK-macro can be any allowed C++-identifier,
*/
template<uint32 ACTUAL_SIZE, uint32 ALLOWED_SIZE>
struct ValidSizeConstraint
{
static void constraint()
{
STATIC_CHECK(fuck_allowed_size_is_too_small,
(ACTUAL_SIZE > ALLOWED_SIZE));
}
ValidSizeConstraint()
{
void (*p)() = constraint;
(*p)();//call function, only to make compiler warning about unused variable go away, will get optimized away
}
};
/**
* static checks
* usage:
* struct B {}; struct D : B { };
* ...Derived_from<D,B>();
*/
template<class T, class B> struct Derived_from
{
static void constraints(T* p) { B* pb = p; pb = pb;}
Derived_from() { void(*p)(T*) = constraints; p = p;}
};
template<class T1, class T2> struct Can_copy
{
static void constraints(T1 a, T2 b) { T2 c = a; b = a; c = a; b = a; }
Can_copy() { void(*p)(T1,T2) = constraints;}
};
template<class T1, class T2 = T1> struct Can_compare
{
static void constraints(T1 a, T2 b) { a==b; a!=b; a<b; }
Can_compare() { void(*p)(T1,T2) = constraints;}
};
}//namespace common
#endif /*COMPILETIMECONSTRAINTS_H_*/

View File

@ -0,0 +1,175 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* Contains STL like algorithms.
* \file SAlgorithm.h
* \ingroup sstl
*/
#ifndef SALGORITHM_H_
#define SALGORITHM_H_
#include "SIteratorBaseTypes.h"
/**
* returns minimum of two values
* \param T type of values
* \param t1 first value
* \param t2 second value
* \return minimum of t1 and t2
*/
template<typename T>
inline const T& smin(const T& t1, const T& t2)
{
return (t1 < t2 ? t1 : t2);
}
/**
* returns maximum of two values
* \param T type of values
* \param t1 first value
* \param t2 second value
* \return maximum of t1 and t2
*/
template<typename T>
inline const T& smax(const T& t1, const T& t2)
{
return (t1 > t2 ? t1 : t2);
}
/**
* swaps two values
* \param T type of values
* \param t1 first value
* \param t2 second value
*/
template<typename T>
inline void sswap(T& t1, T& t2)
{
T t = t1;
t1 = t2;
t2 = t;
}
/**
* finds a value in a given iterator range
* \param InputIterator type of iterators
* \param EqualityCompareable type of value to find
* \param first begin of range
* \param last and of range
* \param value value to find in range
* \return iterator to first element equal to value in range
*/
template<
typename InputIterator,
typename EqualityCompareable>
inline InputIterator sfind(
InputIterator first,
InputIterator last,
const EqualityCompareable& value)
{
return sfind(
first,
last,
value,
typename SIteratorTraits<InputIterator>::iterator_category());
}
/**
* implementation of sfind for input iterators
* \see sfind()
*/
template<
typename InputIterator,
typename EqualityCompareable>
inline InputIterator sfind(
InputIterator first,
InputIterator last,
const EqualityCompareable& value,
SInputIteratorTag)
{
while (!(first == last) && !(*first == value))
{
++first;
}
return first;
}
/**
* removes all elements equal to a value from a range and copies it to another
* \param InputIterator type of input range iterators
* \param OutputIterator type of result range iterator
* \param EqualityCompareable type of value to remove from input range
* \param first begin of input range
* \param last end of input range
* \param result begin iterator of result range
* \param value value to remove
* \return end of result range
*/
template<
typename InputIterator,
typename OutputIterator,
typename EqualityCompareable>
inline OutputIterator sremove_copy(
InputIterator first,
InputIterator last,
OutputIterator result,
const EqualityCompareable& value)
{
while (first != last)
{
if (!(*first == value))
{
*result = *first;
++result;
}
++first;
}
return result;
}
/**
* removes all elements of a given value from a range
* \param ForwardIterator type of range iterator
* \param EqualityCompareable type of value to remove
* \param first begin of range
* \param last end of range
* \param value value to remove from range
* \return iterator to result range
*/
template<
typename ForwardIterator,
typename EqualityCompareable>
ForwardIterator sremove(
ForwardIterator first,
ForwardIterator last,
const EqualityCompareable& value)
{
first = sfind(first, last, value);
ForwardIterator i = first;
return first == last ? first : sremove_copy(++i, last, first, value);
}
template<
typename InputIterator,
typename EqualityComparable>
typename SIteratorTraits<InputIterator>::difference_type scount(
InputIterator first, InputIterator last,
const EqualityComparable& value)
{
typename SIteratorTraits<InputIterator>::difference_type result = 0;
while (first != last)
{
if (*first == value)
{
++result;
}
++first;
}
return result;
}
#endif /*SALGORITHM_H_*/

View File

@ -0,0 +1,38 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* Contains basic type traits.
* \file SBaseTypes.h
* \ingroup sstl
*/
#ifndef SBASETYPES_H_
#define SBASETYPES_H_
/**
* type traits
* \param T type to get traits from
*
* This class may be used to save some type work.
*/
template<typename T>
struct STypeTraits
{
/** unsigned integral type */
typedef unsigned int size_type;
/** signed integral type */
typedef signed int difference_type;
/** type of T itsself */
typedef T value_type;
/** pointer to T */
typedef T* pointer;
/** reference to T */
typedef T& reference;
/** const reference to T */
typedef const T& const_reference;
};
#endif /*SBASETYPES_H_*/

View File

@ -0,0 +1,141 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* Contains base types for iterators.
* \file SIteratorBaseTypes.h
* \ingroup sstl
*/
#ifndef SITERATORBASETYPES_H_
#define SITERATORBASETYPES_H_
/**
* input iterator
*
* \section Description
* May advance through a iterator range. Reads each
* value exactly one time.
*/
struct SInputIteratorTag {};
/**
* output iterator
*
* \section Description
* May advance through a iterator range and alter values.
*/
struct SOutputIteratorTag {};
/**
* forward iterator
*
* \section Description
* May advance through a iterator range and read each value
* more than on time.
*/
struct SForwardIteratorTag : public SInputIteratorTag {};
/**
* bidirectional iterator
*
* \section Description
* May go through a iterator range in both directions and
* read each value more than one time
*/
struct SBidirectionalIteratorTag : public SForwardIteratorTag {};
/**
* random access iterator
*
* \section Description
* May go through a iterator range like a pointer through an
* array and read each value more than one time.
*/
struct SRandomAccessIteratorTag : public SBidirectionalIteratorTag {};
/**
* optional base class for iterators
* \param Category iterators category
* \param T type iterator points to
* \param Distance signed integral type
* \param Pointer pointer to T
* \param Reference reference to T
*
* Classes may subclass this class to save some typedef work.
*/
template<
typename Category,
typename T,
typename Distance = signed int,
typename Pointer = T*,
typename Reference = T&>
struct SIterator
{
/** the iterators category */
typedef Category iterator_category;
/** type of value iterator points to */
typedef T value_type;
/** signed integral type */
typedef Distance difference_type;
/** pointer to value type */
typedef Pointer pointer;
/** reference to value type */
typedef Reference reference;
};
/**
* traits for iterators
* \param Iterator iterator to generate traits for
*/
template<typename Iterator>
struct SIteratorTraits
{
/** the iterators category */
typedef typename Iterator::iterator_category iterator_category;
/** type of value iterator points to */
typedef typename Iterator::value_type value_type;
/** signed integral type */
typedef typename Iterator::difference_type difference_type;
/** pointer to value */
typedef typename Iterator::pointer pointer;
/** reference to value */
typedef typename Iterator::reference reference;
};
/**
* special implementation for pointers
* \param T type of value for whose pointer traits are generated
*
* \see SIteratorTraits
*/
template<typename T>
struct SIteratorTraits<T*>
{
typedef SRandomAccessIteratorTag iterator_category;
typedef T value_type;
typedef signed int difference_type;
typedef value_type* pointer;
typedef value_type& reference;
};
/**
* special implementation for const pointers
* \param T type of value for whose const pointer traits are generated
*
* \see SIteratorTraits
*
*/
template<typename T>
struct SIteratorTraits<const T*>
{
typedef SRandomAccessIteratorTag iterator_category;
typedef T value_type;
typedef signed int difference_type;
typedef const value_type* pointer;
typedef const value_type& reference;
};
#endif /*SITERATORBASETYPES_H_*/

View File

@ -0,0 +1,441 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#ifndef SLINKEDLIST_H_
#define SLINKEDLIST_H_
#include "util/SBaseTypes.h"
#include "util/SIteratorBaseTypes.h"
#include "util/CompileTimeConstraints.h"
#include <cassert>
template<typename T>
class SLinkedListSetNode
{
public:
typedef T value_type;
SLinkedListSetNode() :
fpNext(0L),
fAddedToList(false)
{}
T* getNext() const
{
return fpNext;
}
void setNext(T* pNext)
{
fpNext = pNext;
}
void addToList()
{
assert(!fAddedToList);
fAddedToList = true;
}
void removeFromList()
{
fAddedToList = false;
}
private:
SLinkedListSetNode(const SLinkedListSetNode&);
SLinkedListSetNode& operator=(const SLinkedListSetNode&);
T* fpNext;
bool fAddedToList;
};
template<typename T>
class SLinkedListSetIterator;
template<typename T>
class SLinkedListSet
: common::Derived_from<T, SLinkedListSetNode<T> >
{
private:
/** type of list itsself */
typedef SLinkedListSet<T> self_type;
public:
/** type of values stored in vector */
typedef typename STypeTraits<T>::value_type value_type;
/** pointer to value */
typedef typename STypeTraits<T>::pointer pointer;
/** reference to value */
typedef typename STypeTraits<T>::reference reference;
/** const reference to value */
typedef typename STypeTraits<T>::const_reference const_reference;
/** unsigned integral type */
typedef typename STypeTraits<T>::size_type size_type;
/** signed integral type */
typedef typename STypeTraits<T>::difference_type difference_type;
/** iterator type */
typedef SLinkedListSetIterator<T> iterator;
/** const iterator type */
typedef SLinkedListSetIterator<const T> const_iterator;
SLinkedListSet() :
fpFirst(0L),
fpLast(0L)
{
clear();
}
/**
* @note
* O(n)!
* @todo
* Maybe a field would be better
*/
size_type size() const
{
size_type size = (fpFirst) ? 1 : 0;
for (const T* pNode = fpFirst; pNode != fpLast; pNode = pNode->getNext())
{
++size;
}
return size;
}
bool empty() const
{
return (fpFirst == 0L);
}
void clear()
{
while (!empty())
{
pop_front();
}
fpFirst = 0L;
fpLast = 0L;
}
const_reference front() const
{
assert(fpFirst);
return *fpFirst;
}
reference front()
{
return const_cast<reference>(
static_cast<const self_type&>(
*this).front());
}
const_reference back() const
{
assert(fpLast);
return *fpLast;
}
reference back()
{
return const_cast<reference>(
static_cast<const self_type&>(
*this).back());
}
void push_front(T& node)
{
if (contains_node(&node))
{
return;
}
node.addToList();
node.setNext(fpFirst);
fpFirst = &node;
if (!fpLast)
{//inserted first node
fpLast = fpFirst;
fpFirst->setNext(0L);
}
}
void push_back(T& node)
{
if (empty())
{//inserted first node
fpFirst = &node;
}
else
{
if (contains_node(&node))
{
return;
}
fpLast->setNext(&node);
}
node.addToList();
fpLast = &node;
fpLast->setNext(0L);
}
void pop_front()
{
if (!fpFirst)
{
return;
}
fpFirst->removeFromList();
fpFirst = fpFirst->getNext();
if (!fpFirst)
{//removed last element
fpLast = 0L;
}
}
void pop_back();
iterator begin()
{
return iterator(fpFirst);
}
const_iterator begin() const
{
return const_iterator(fpFirst);
}
iterator end()
{
return iterator(0L);
}
const_iterator end() const
{
return const_iterator(0L);
}
iterator erase(iterator pos);
iterator insert(iterator pos, T& value);
void remove(const T& value);
bool contains(const T& value) const
{
return contains_node(&value);
}
private:
SLinkedListSet(const SLinkedListSet&);
SLinkedListSet& operator=(const SLinkedListSet&);
T* findPredecessor(const T* pNode) const
{
T* pResult = fpFirst;
while ((pResult != 0L) && (pResult->getNext() != pNode))
{
pResult = pResult->getNext();
}
return pResult;
}
bool contains_node(const T* pNodeToFind) const;
T* fpFirst;
T* fpLast;
};
template<typename T>
bool SLinkedListSet<T>::contains_node(const T* pNodeToFind) const
{
T* pNode = fpFirst;
while (pNode != 0L)
{
if (pNodeToFind == pNode)
{
return true;
}
pNode = pNode->getNext();
}
return false;
}
template<typename T>
void SLinkedListSet<T>::pop_back()
{
if (!fpLast)
{
return;
}
fpLast->removeFromList();
if (fpFirst == fpLast)
{
clear();
}
else
{
fpLast = findPredecessor(fpLast);
assert(fpLast);
fpLast->setNext(0L);
}
}
template<typename T>
typename SLinkedListSet<T>::iterator SLinkedListSet<T>::erase(
SLinkedListSet<T>::iterator pos)
{
if (!fpFirst)
{
return end();
}
iterator next = pos;
++next;
if (pos == begin())
{//remove first element
pop_front();
}
else
{
pos->removeFromList();
T* pNode = findPredecessor(pos.operator->());
assert(pNode);
if (pNode->getNext() == fpLast)
{//removing last element
fpLast = pNode;
}
pNode->setNext(pos->getNext());
}
return next;
}
template<typename T>
typename SLinkedListSet<T>::iterator SLinkedListSet<T>::insert(
SLinkedListSet<T>::iterator pos,
T& value)
{
if (contains_node(&value))
{
return pos;
}
if (empty() || (pos == begin()))
{
push_front(value);
}
else if (pos == end())
{
push_back(value);
}
else
{
value.addToList();
T* pNode = findPredecessor(pos.operator->());
assert(pNode);
value.setNext(pNode->getNext());
pNode->setNext(&value);
}
return iterator(&value);
}
template<typename T>
void SLinkedListSet<T>::remove(const T& value)
{
if (&value == fpFirst)
{
pop_front();
}
else if (&value == fpLast)
{
pop_back();
}
else
{
const_cast<T&>(value).removeFromList();
T* pNode = findPredecessor(&value);
if (pNode)
{
pNode->setNext(value.getNext());
}
}
}
template <typename T>
bool operator==(
const SLinkedListSetIterator<T>& x,
const SLinkedListSetIterator<T>& y);
template <typename T>
bool operator!=(
const SLinkedListSetIterator<T>& x,
const SLinkedListSetIterator<T>& y);
template<typename T>
class SLinkedListSetIterator
{
public:
/** the iterators category */
typedef SForwardIteratorTag iterator_category;
/** value type of iterator */
typedef typename STypeTraits<T>::value_type value_type;
/** reference to value */
typedef typename STypeTraits<T>::reference reference;
/** pointer to value */
typedef typename STypeTraits<T>::pointer pointer;
/** signed integral type */
typedef typename STypeTraits<T>::difference_type difference_type;
SLinkedListSetIterator(T* pValue) :
fpValue(pValue)
{}
SLinkedListSetIterator(const SLinkedListSetIterator& rhs) :
fpValue(rhs.fpValue)
{}
SLinkedListSetIterator& operator=(const SLinkedListSetIterator& rhs)
{
fpValue = rhs.fpValue;
return *this;
}
SLinkedListSetIterator& operator++()
{
fpValue = fpValue->getNext();
return *this;
}
reference operator*()
{
return *fpValue;
}
pointer operator->()
{
return fpValue;
}
private:
friend bool operator==<T>(
const SLinkedListSetIterator<T>&,
const SLinkedListSetIterator<T>&);
friend bool operator!=<T>(
const SLinkedListSetIterator<T>&,
const SLinkedListSetIterator<T>&);
T* fpValue;
};
template<typename T>
inline bool operator==(
const SLinkedListSetIterator<T>& x,
const SLinkedListSetIterator<T>& y)
{
return (x.fpValue == y.fpValue);
}
template<typename T>
inline bool operator!=(
const SLinkedListSetIterator<T>& x,
const SLinkedListSetIterator<T>& y)
{
return !(x == y);
}
#endif /*SLINKEDLIST_H_*/

View File

@ -0,0 +1,57 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* Contains helpers to make C++ classes uncopyable, i.e. declare copy
* constructor and assignment operator private.
* \file Uncopyable.h
*/
#ifndef UNCOPYABLE_H_
#define UNCOPYABLE_H_
/**
* The macro MAKE_UNCOPYABLE expands to a declaration of copy constructor and
* assignment operator.
* \par Usage example
* \code
* class MyClass
* {
* MAKE_UNCOPYABLE(MyClass)
* public:
* //...
* };
* \endcode
*/
#ifdef MAKE_UNCOPYABLE
#error "MAKE_UNCOPYABLE was already defined!"
#endif
// PRQA S 1030 3
#define MAKE_UNCOPYABLE(TypeName) \
TypeName(const TypeName&); \
TypeName& operator=(const TypeName&);
namespace common
{
/**
* Inheriting from Uncopyable makes sure that no copies of any subclass
* are instantiated accidently because the C++ compiler will raise an error.
*
* \author oliver.mueller
*/
class Uncopyable
{
protected:
Uncopyable(){}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
}//namespace common
#endif /*UNCOPYABLE_H_*/

24
2016/ppc/gps/Project.meta Normal file
View File

@ -0,0 +1,24 @@
Project {
ExecutableConfig UnitTest {
Files "src/**/*.cpp"
ExcludeFiles "src/ac/*.cpp"
Files "test/**/*.cpp"
IncludeDir "include"
IncludeDir "test/include"
IncludeDir "common/include"
ArtifactName "gpsTests.exe"
PostSteps {
CommandLine "$(OutputDir)/$(ArtifactName) -r xml --out $(OutputDir)/test_$(ArtifactName).xml", filter: run, default: off
}
DefaultToolchain GCC {
Compiler CPP {
Flags "-g -Wall -fpermissive -fmessage-length=0"
Define "UNIT_TEST"
}
Compiler C {
Flags "-g -Wall -fpermissive -fmessage-length=0"
Define "UNIT_TEST"
}
}
}
}

View File

@ -0,0 +1,36 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#ifndef AC_PUSHER_H_
#define AC_PUSHER_H_
#include "gps/IACPusher.h"
namespace android
{
class ICaimTransceiver;
}
namespace gps
{
class GpsAcPusher : public IACPusher
{
public:
virtual void pushGPSCoordinates(sint32 latMs, sint32 longMs);
private:
uint8 fPosition[15];
ICaimTransceiver& fCaimTransceiver;
static const uint8 LONGITUDE_OFFSET = 0;
static const uint8 LATITUDE_OFFSET = 4;
static const uint8 HEADING_OFFSET = 8;
static const uint8 HEIGHT_OFFSET = 9;
static const uint8 QUALITY_OFFSET = 11;
static const uint8 SPEED_OFFSET = 13;
};
} // namespace gps
#endif /* end of include guard */

View File

@ -0,0 +1,21 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#ifndef IAC_PUSHER_H_
#define IAC_PUSHER_H_
#include "commonTypes.h"
namespace gps
{
class IGpsACPusher
{
public:
virtual void pushGPSCoordinates(sint32 latMs, sint32 longMs) = 0;
};
} // namespace gps
#endif /* end of include guard */

View File

@ -0,0 +1,236 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#ifndef BUSID_H_
#define BUSID_H_
#include "commonTypes.h"
#include "util/Uncopyable.h"
//forward declarations
class BusIdIterator;
/**
* Abstraction for bus ids used throughout the system.
* @author matthias.kessler
*
* BusId contains constants for all busses used and provides an iterator
* to access them. Each BusId will have an index that is unique in the system.
*/
class BusId
{
public:
enum { MAX_INDEX = 4 };
/** iterator over BusIds */
typedef BusIdIterator iterator;
/** maximum number of busses, used to allocate static memory */
static const uint8 MAX_NUMBER_OF_BUSSES = MAX_INDEX;
static const uint8 NUMBER_OF_LIN_BUSSES = 1;
static const BusId BODYCAN;
static const BusId LIN;
static const BusId TAS;
static const BusId SELFDIAG;
static const BusId INVALID; //MUST be last BusId and is not part of MAX_NUMBER_OF_BUSSES
/**
* constructor
* @param name string representation of BusId
*/
explicit BusId(const char* name);
/**
* @return the BusIds name
*/
const char* getName() const
{
return fpName;
}
/**
* @return the BusIds unique index
*/
uint8 toIndex() const
{
return fId;
}
uint8 toCANIndex() const;
uint8 toLINIndex() const;
/**
* @param index index of BusId to access
* @return BusId at given index
*/
static const BusId& get(uint8 index);
/**
* @return iterator to first BusId
*/
static iterator begin();
/**
* @return iterator one past last BusId
*/
static iterator end();
/**
* @return total number of busses (excluding INVALID)
*/
static uint8 numberOfBusses()
{
return sfIdCount;
}
private:
MAKE_UNCOPYABLE(BusId)
//friends
friend bool operator==(const BusId& x, const BusId& y);
friend bool operator!=(const BusId& x, const BusId& y);
friend class BusIdIterator;
//fields
uint8 fId;
const char* fpName;
//static fields
static uint8 sfIdCount;
static BusId* sfBusId[MAX_NUMBER_OF_BUSSES];
};
/**
* Compares two given BusIds
* @param x first BusId to compare
* @param y second BusId to compare
* @return
* - true BusIds are equal
* - false BusIds are not equal
*/
inline bool operator==(const BusId& x, const BusId& y)
{
return (x.fId == y.fId);
}
/**
* Compares two given BusIds
* @param x first BusId to compare
* @param y second BusId to compare
* @return
* - true BusIds are not equal
* - false BusIds are equal
*/
inline bool operator!=(const BusId& x, const BusId& y)
{
return (x.fId != y.fId);
}
/**
* Iterator for BusIds.
* @author matthias.kessler
*/
class BusIdIterator
{
public:
/** pointer to a BusId */
typedef BusId* pointer;
/** reference to a BusId */
typedef BusId& reference;
/**
* constructor
* @param pBusId pointer to BusId this iterator points initially to
*/
explicit BusIdIterator(BusId* pBusId) :
fpBusId(pBusId)
{}
/**
* copy constructor
* @param itr iterator to copy from
*/
BusIdIterator(const BusIdIterator& itr) :
fpBusId(itr.fpBusId)
{}
/**
* assignment operator
* @param itr iterator to copy from
*/
BusIdIterator& operator=(const BusIdIterator& itr)
{
if (&itr != this)
{
fpBusId = itr.fpBusId;
}
return *this;
}
/**
* @return pointer to BusId iterator currently points to
*/
pointer operator->() const
{
return fpBusId;
}
/**
* @return reference to BusId iterator currently points to
*/
reference operator*() const
{
return *fpBusId;
}
/**
* prefix increment operator
* @return next iterator
*/
BusIdIterator& operator++()
{
if (fpBusId->toIndex() < BusId::sfIdCount-2)//-2 because of INVALID is last BusId
{
fpBusId = BusId::sfBusId[fpBusId->toIndex() + 1];
}
else
{
fpBusId = 0L;
}
return *this;
}
private:
//friends
friend bool operator==(const BusIdIterator& x, const BusIdIterator& y);
friend bool operator!=(const BusIdIterator& x, const BusIdIterator& y);
//fields
BusId* fpBusId;
};
/**
* compares two BusIdIterators
* @param x first BusIdIterators to compare
* @param y second BusIdIterators to compare
* @return
* - true BusIdIterators are equal
* - false BusIdIterators are not equal
*/
inline bool operator==(const BusIdIterator& x, const BusIdIterator& y)
{
return (x.fpBusId == y.fpBusId);
}
/**
* compares two BusIdIterators
* @param x first BusIdIterators to compare
* @param y second BusIdIterators to compare
* @return
* - true BusIdIterators are not equal
* - false BusIdIterators are equal
*/
inline bool operator!=(const BusIdIterator& x, const BusIdIterator& y)
{
return (x.fpBusId != y.fpBusId);
}
#endif /*BUSID_H_*/

View File

@ -0,0 +1,18 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* @file BusIdMask.h
*/
#ifndef BUSIDMASK_H_
#define BUSIDMASK_H_
#include "util/Mask.h"
#include "busId/BusId.h"
typedef Mask<BusId, uint32> BusIdMask;
#endif /*BUSIDMASK_H_*/

View File

@ -0,0 +1,44 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#ifndef I_CAN_TRANSCEIVER_H_
#define I_CAN_TRANSCEIVER_H_
#include "can/canframes/CANFrame.h"
namespace can
{
class ICANTransceiver
{
public:
enum ErrorCode
{
CAN_ERR_OK,
CAN_ERR_TX_FAIL
};
virtual ErrorCode init() = 0;
virtual void shutdown() = 0;
virtual ErrorCode open() = 0;
virtual ErrorCode close() = 0;
virtual ErrorCode mute() = 0;
virtual ErrorCode unmute() = 0;
virtual ErrorCode write(const can::CANFrame& frame) = 0;
virtual uint32 getBaudrate() const = 0;
virtual uint16 getHwQueueTimeout() const = 0;
};
} // namespace can
#endif /* end of include guard */

View File

@ -0,0 +1,181 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* Contains Cpp2CAN CANFrame.
* @file CANFrame.h
* @ingroup cpp2can
*/
#ifndef CANFRAME_H
#define CANFRAME_H
#include "commonTypes.h"
#include <cassert>
namespace can
{
/**
* Class representing a CANFrame.
* @author matthias.kessler
*
* A object of type CANFrame does not provide any payload-buffer by default.
* It has to be provided with buffers by using a certain constructor or the
* setPayload() method.
*
* @note
* CANFrame may be used as base class for special frame classes providing
* the programmer with explicit methods to access the signals that are
* encoded in the CANFrames payload.
*/
class CANFrame
{
public:
/** bitmask to extract sender */
static const uint8 SENDER_MASK = 0xFF;
/** overhead of a CANFrame (in bit) */
static const uint8 CAN_OVERHEAD_BITS = 47;
/** maximum payload length of a CANFrame */
static const uint8 MAX_FRAME_LENGTH = 8;
/** maximum value of a CANFrame id */
static const uint16 MAX_FRAME_ID = 0x7FF;
/**
* @post getId() == 0x00
* @post getPayload() == NULL
* @post getPayloadLength() == 0
* @post getTimestamp() == 0
*/
CANFrame();
/**
* Copy constructor
* @param frame CANFrame to copy content from
*/
CANFrame(const CANFrame& frame);
/**
* Constructor initializing id, payload and length
*
* @pre id <= MAX_FRAME_ID
* @pre length <= MAX_FRAME_LENGTH
* @throws assertion
*
* The payload will not be copied, it is passed as a
* reference and CANFrame will work on this payload!
*/
CANFrame(uint16 id, uint8 payload[], uint8 length);
uint16 getId() const
{
return fId;
}
void setId(uint16 id)
{
this->fId = id;
}
/**
* @return pointer to modifiable payload of this CANFrame
*/
uint8* getPayload()
{
return fpPayload;
}
/**
* @return pointer to read only payload of this CANFrame
*/
const uint8* getPayload() const
{
return fpPayload;
}
/**
* Sets the CANFrames payload and length
*
* @note
* This method just sets a pointer to the payload and does not copy it!
*
* @post getPayload() == payload
* @post getPayloadLength() == length
* @post getMaxPayloadLength() == length
*/
void setPayload(uint8 payload[], uint8 length)
{
fpPayload = payload;
fPayloadLength = length;
fMaxPayloadLength = length;
}
/**
* @pre getPayload() != NULL
* @pre length <= getMaxPayloadLength()
* @throws assertion
*/
void setPayloadLength(uint8 length);
uint8 getPayloadLength() const
{
return fPayloadLength;
}
uint8 getMaxPayloadLength() const
{
return fMaxPayloadLength;
}
/**
* Assigns content of a CANFrame to another.
* @param canFrame frame to copy from
* @return reference to frame with new content
* @pre getMaxPayloadLength() >= canFrame.getPayloadLength()
* @throws assertion
*/
CANFrame& operator=(const CANFrame& canFrame);
/**
* @return modifiable reference to timestamp
*/
uint64& getTimestamp()
{
return fTimestamp; // PRQA S 4024
}
/**
* @return read only access to timestamp
*/
const uint64& getTimestamp() const
{
return fTimestamp;
}
bool isExtended() const { return false; } /* TODO: cleanup */
protected:
friend bool operator==(const CANFrame& frame1, const CANFrame& frame2);
uint8* fpPayload;
uint16 fId;
uint8 fPayloadLength;
uint8 fMaxPayloadLength;
uint64 fTimestamp;
};
/**
* Compares two CANFrames without considering the timestamp
* @param frame1 first frame to compare
* @param frame2 second frame to compare
* @return
* - true if frames are equal
* - false if frames are not equal
*/
bool operator==(const CANFrame& frame1, const CANFrame& frame2);
} /* namespace can */
#endif /* CANFRAME_H */

View File

@ -0,0 +1,79 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* Contains IFilter interface.
* @file IFilter.h
* @ingroup filter
*/
#ifndef IFILTER_H_
#define IFILTER_H_
#include "commonTypes.h"
#include "util/Uncopyable.h"
namespace can
{
//forward declaration
class IMerger;
/**
* common interface for filter classes
* @author matthias.kessler
*/
class IFilter
{
public:
IFilter() {};
/**
* adds a single id to the filter
* @param id id to add
* @post filter.match(id)
*/
virtual void add(uint16 id) = 0;
/**
* adds a range of ids to the filter
* @param from begin of range
* @param to end of range
* @post filter.match(from...to);
*/
virtual void add(uint16 from, uint16 to) = 0;
/**
* checks if a given id matches the filter
* @return
* - true: id matches filter
* - false: id does not match filter
*/
virtual bool match(uint16 id) const = 0;
/**
* clears the filter so that nothing matches
*/
virtual void clear() = 0;
/**
* opens the filters full range
*/
virtual void open() = 0;
/**
* merges filter with a given merger
* @param merger IMerger to merge filter to
*
* This is part of the visitor pattern that is used to
* merge different kinds of filters.
*/
virtual void acceptMerger(IMerger& merger) = 0;
private:
MAKE_UNCOPYABLE(IFilter)
};
} //namespace can
#endif /*IFILTER_H_*/

View File

@ -0,0 +1,62 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* Contains IMerger interface.
* @file IMerger.h
* @ingroup filter
*/
#ifndef _IMERGER_H_
#define _IMERGER_H_
#include "util/Uncopyable.h"
namespace can
{
//forward declarations
class BitFieldFilter;
class AbstractStaticBitFieldFilter;
class IntervalFilter;
/**
* interface for class that are able to merge with other filter classes
* @class IMerger
* @author gerd.schaefer
*
* @see BitFieldFilter
* @see AbstractStaticBitFieldFilter
* @see IntervalFilter
*/
class IMerger
{
public:
IMerger() {}
/**
* merges with a BitFieldFilter
* @param filter BitFieldFilter to merge with
*/
virtual void mergeWithBitField(BitFieldFilter& filter) = 0;
/**
* merges with a AbstractStaticBitFieldFilter
* @param filter AbstractStaticBitFieldFilter to merge with
*/
virtual void mergeWithStaticBitField(AbstractStaticBitFieldFilter& filter) = 0;
/**
* merges with a IntervalFilter
* @param filter IntervalFilter to merge with
*/
virtual void mergeWithInterval(IntervalFilter& filter) = 0;
private:
MAKE_UNCOPYABLE(IMerger)
};
} //namespace can
#endif //_IMERGER_H_

View File

@ -0,0 +1,148 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* Contains IntervalFilter class.
* @file IntervalFilter.h
* @ingroup filter
*/
#ifndef _INTERVALFILTER_H_
#define _INTERVALFILTER_H_
#include "commonTypes.h"
#include "can/canframes/CANFrame.h"
#include "can/filter/IFilter.h"
#include "can/filter/IMerger.h"
#include "util/Uncopyable.h"
namespace can
{
/**
* Cpp2CAN IntervalFilter
* @author gerd.schaefer, matthias.kessler
*
* @see IFilter
*/
class IntervalFilter :
public IFilter
{
public:
/** maximum id the filter may take */
static const uint16 MAX_ID = CANFrame::MAX_FRAME_ID;
/**
* constructor
* @post getLowerBound() == MAX_ID
* @post getUpperBound() == 0x0
*
* Nothing wil be accepted by default
*/
IntervalFilter();
/**
* constructor initializing an interval
* @param from first id that will be accepted
* @param to last id that will be accepted
* @pre from <= MAX_ID
* @pre to <= MAX_ID
* @post getLowerBound() == from
* @post getUpperBound() == to
*
* @note
* If from or to exceed MAX_ID, they will be set to MAX_ID.
*/
explicit IntervalFilter(uint16 from, uint16 to);
/**
* @see IFilter::add()
* @param id id to add to filter
* @pre id <= MAX_ID, otherwise no effect
* @post getLowerBound() == min(id, getLowerBound())
* @post getUpperBound() == max(id, getUpperBound())
*
* @note
* This call is equal to add(id, id).
*/
virtual void add(uint16 id)
{
if (id <= MAX_ID)
{
add(id, id);
}
}
/**
* @see IFilter::add()
* @param from lower bound of interval to add
* @param to upper bound of interval to add
* @pre from <= MAX_ID
* @pre to <= MAX_ID
* @post getLowerBound() == min(from, getLowerBound())
* @post getUpperBound() == max(to, getUpperBound())
*
* If from or to exceed MAX_ID, they will be set to MAX_ID.
*
* This call will not replace the current filter configuration, but
* adjust lower and upper bound of the filter according to the parameters.
*/
virtual void add(uint16 from, uint16 to);
/**
* checks if an id matches the filter
* @param id id to check
* @return
* - true: filter matches id
* - false: id is not in filters range
*/
virtual bool match(uint16 id) const
{
return (id >= fFrom) && (id <= fTo);
}
/**
* @see IFilter::acceptMerger()
*/
virtual void acceptMerger(IMerger& merger)
{
merger.mergeWithInterval(*this);
}
/**
* @see IFilter::clear();
*/
virtual void clear();
/**
* @see IFilter::open();
*/
virtual void open();
/**
* @return lower bound of filter
*/
uint16 getLowerBound() const
{
return fFrom;
}
/**
* @return upper bound of filter
*/
uint16 getUpperBound() const
{
return fTo;
}
private:
MAKE_UNCOPYABLE(IntervalFilter)
//fields
uint16 fFrom;
uint16 fTo;
};
} /*namespace can*/
#endif //_INTERVALFILTER_H_

View File

@ -0,0 +1,50 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
/**
* Contains interface ICANFrameListener.
* @file ICANFrameListener.h
* @ingroup framemgmt
*/
#ifndef ICANFRAMELISTENER_H
#define ICANFRAMELISTENER_H
#include "util/SLinkedListSet.h"
#include "util/Uncopyable.h"
namespace can
{
class CANFrame;
class IFilter;
/**
* CANFrameListener interface
* @author matthias.kessler
*
* An ICANFrameListener subclass is a class interested in the reception
* of CANFrames. Therefore it needs to register at an AbstractCANTransceiver.
*/
class ICANFrameListener :
public SLinkedListSetNode<ICANFrameListener>
{
MAKE_UNCOPYABLE(ICANFrameListener)
public:
ICANFrameListener() {}
/**
* This method notifies the listener of a CANFrame reception.
*/
virtual void frameReceived(const CANFrame& canFrame) = 0;
/**
* Returns the ICANFrameListeners filter.
*/
virtual IFilter& getFilter() = 0;
};
} //namespace can
#endif // ICANFRAMELISTENER_H

View File

@ -0,0 +1,48 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#ifndef GPSCONVERTER_H_
#define GPSCONVERTER_H_
#include "commonTypes.h"
#include "can/framemgmt/ICANFrameListener.h"
#include "can/filter/IntervalFilter.h"
namespace can
{
class CANFrame;
class ICANTransceiver;
}
namespace gps
{
class IGpsACPusher;
class GpsConverter :
public can::ICANFrameListener
{
public:
enum { GPS_FRAME_ID = 0x34a }; //NavGps1
GpsConverter(can::ICANTransceiver& transceiver, IGpsACPusher& acPusher);
/* ICANFrameListener */
virtual void frameReceived(const can::CANFrame& canFrame);
virtual can::IFilter& getFilter()
{
return fCanFilter;
}
private:
can::ICANTransceiver& fCanTransceiver;
can::IntervalFilter fCanFilter;
IGpsACPusher& fAcPusher;
sint32 fLastLatInMs;
sint32 fLastLongInMs;
};
} // namespace gps
#endif /* end of include guard */

7
2016/ppc/gps/rakefile.rb Normal file
View File

@ -0,0 +1,7 @@
desc "run unittests"
task :runTests do
sh "bake -b UnitTest -a black --include_filter run"
end
task :default => :run

View File

@ -0,0 +1,33 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#include "gps/AcPusher.h"
#include "android/caim/base/ICaimTransceiver.h"
#include "util/endian.h"
namespace gps
{
void GpsAcPusher::pushGPSCoordinates(sint32 latMs, sint32 longMs)
{
uint8 newPosition[sizeof(fPosition)];
writeMem32(newPosition + LONGITUDE_OFFSET, longMs);
writeMem32(newPosition + LATITUDE_OFFSET, latMs);
writeMem16(newPosition + HEIGHT_OFFSET, 0);
writeMem16(newPosition + SPEED_OFFSET, 0);
newPosition[HEADING_OFFSET] = 0;
writeMem16(newPosition + QUALITY_OFFSET, 0);
if (memcmp(newPosition, fPosition, sizeof(fPosition)))
{
memcpy(fPosition, newPosition, sizeof(fPosition));
fCaimTransceiver.push(POSITION_COMMAND, fPosition, sizeof(fPosition));
}
}
} // namespace gps

View File

@ -0,0 +1,99 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#include "can/canframes/CANFrame.h"
namespace can
{
//define const variables for GCC
#ifdef __GNUC__
const uint8 CANFrame::SENDER_MASK;
const uint8 CANFrame::CAN_OVERHEAD_BITS;
const uint8 CANFrame::MAX_FRAME_LENGTH;
const uint16 CANFrame::MAX_FRAME_ID;
#endif
CANFrame::CANFrame() :
fpPayload(0L),
fId(0),
fPayloadLength(0),
fMaxPayloadLength(0),
fTimestamp(0)
{}
CANFrame::CANFrame(const CANFrame& frame) :
fpPayload(frame.fpPayload),
fId(frame.fId),
fPayloadLength(frame.fPayloadLength),
fMaxPayloadLength(frame.fMaxPayloadLength),
fTimestamp(frame.fTimestamp)
{
}
CANFrame::CANFrame(uint16 id, uint8 payload[], uint8 length) :
fpPayload(payload),
fId(id),
fPayloadLength(length),
fMaxPayloadLength(length)
{
assert(id <= MAX_FRAME_ID);
assert(length <= MAX_FRAME_LENGTH);
}
CANFrame& CANFrame::operator=(const CANFrame& canFrame)
{
if (&canFrame != this)
{
if (fMaxPayloadLength < canFrame.fPayloadLength)
{
assert(fMaxPayloadLength >= canFrame.fPayloadLength);
}
fId = canFrame.fId;
for (uint8 i = 0; i < canFrame.fPayloadLength; ++i)
{
fpPayload[i] = canFrame.fpPayload[i];
}
fPayloadLength = canFrame.fPayloadLength;
fTimestamp = canFrame.fTimestamp;
}
return *this;
}
void CANFrame::setPayloadLength(uint8 length)
{
if (!fpPayload)
{
assert(fpPayload != 0L);
}
if (length > fMaxPayloadLength)
{
assert(length <= fMaxPayloadLength);
}
fPayloadLength = length;
}
bool operator==(const CANFrame& frame1, const CANFrame& frame2)
{
if (frame1.fId != frame2.fId)
{
return false;
}
if (frame1.fPayloadLength != frame2.fPayloadLength)
{
return false;
}
for (uint8 i = 0; i < frame1.fPayloadLength; i++)
{
if (frame1.fpPayload[i] != frame2.fpPayload[i])
{
return false;
}
}
return true;
}
} //namespace can

View File

@ -0,0 +1,69 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#include "can/filter/IntervalFilter.h"
#include "util/SAlgorithm.h"
namespace can
{
#ifdef __GNUC__
const uint16 IntervalFilter::MAX_ID;
#endif
IntervalFilter::IntervalFilter()
{
clear();
}
IntervalFilter::IntervalFilter(uint16 from, uint16 to) :
fFrom(from),
fTo(to)
{
if (from > MAX_ID)
{
fFrom = MAX_ID;
}
if (to > MAX_ID)
{
fTo = MAX_ID;
}
}
void IntervalFilter::add(uint16 from, uint16 to)
{
if (from > MAX_ID)
{
from = MAX_ID;
}
if (to > MAX_ID)
{
to = MAX_ID;
}
//assert order
if (from > to)
{
sswap(from, to);
}
//adjust lower bound
fFrom = smin(fFrom, from);
//adjust upper bound
fTo = smax(fTo, to);
}
void IntervalFilter::clear()
{
fFrom = MAX_ID;
fTo = 0;
}
void IntervalFilter::open()
{
fFrom = 0x0;
fTo = MAX_ID;
}
} /*namespace can*/

View File

@ -0,0 +1,48 @@
/**
* \copyright
* (c) 2012 - 2015 E.S.R. Labs GmbH (http://www.esrlabs.com)
* All rights reserved.
*/
#include "gps/GpsConverter.h"
#include "ac/IGpsACPusher.h"
#include "can/canframes/CANFrame.h"
#include "can/ICANTransceiver.h"
#include <stdio.h>
using namespace can;
namespace gps
{
GpsConverter::GpsConverter(
ICANTransceiver& transceiver,
IGpsACPusher& acPusher)
: fCanTransceiver(transceiver)
, fCanFilter(GPS_FRAME_ID, GPS_FRAME_ID)
, fAcPusher(acPusher)
{
}
void GpsConverter::frameReceived(const CANFrame& canFrame)
{
const uint8* payload = canFrame.getPayload();
// TOOD implement conversion to arc-msec and call IGpsACPusher
sint32 latInMs = 0; // here add your converted lat
sint32 longInMs = 0; // here add your converted long
if (latInMs != fLastLatInMs || longInMs != fLastLongInMs)
{
// value changed
fAcPusher.pushGPSCoordinates(latInMs, longInMs);
fLastLatInMs = latInMs;
fLastLongInMs = longInMs;
}
}
} // namespace gps

View File

@ -0,0 +1,53 @@
#ifndef CANTRANSCEIVER_MOCK_H_
#define CANTRANSCEIVER_MOCK_H_
#include "can/ICANTransceiver.h"
#include "busId/BusId.h"
namespace can
{
class CanTransceiverMock
: public ICANTransceiver
{
public:
CanTransceiverMock()
{}
virtual ErrorCode init()
{
return CAN_ERR_OK;
}
virtual void shutdown() {}
virtual ErrorCode open()
{
return CAN_ERR_OK;
}
virtual ErrorCode close()
{
return CAN_ERR_OK;
}
virtual ErrorCode mute()
{
return CAN_ERR_OK;
}
virtual ErrorCode unmute()
{
return CAN_ERR_OK;
}
virtual ErrorCode write(const can::CANFrame& frame)
{
return CAN_ERR_OK;
}
virtual uint32 getBaudrate() const
{
return 500000;
}
virtual uint16 getHwQueueTimeout() const
{
return 50;
}
};
} // namespace can
#endif /* end of include guard */

View File

@ -0,0 +1,110 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "commonTypes.h"
#include "can/canframes/CANFrame.h"
#include "gps/GpsConverter.h"
#include "ac/IGpsACPusher.h"
#include "CanTransceiverMock.h"
#include "busId/BusId.h"
using namespace gps;
using namespace common;
using namespace can;
namespace test
{
class GpsAcPusherMock : public gps::IGpsACPusher
{
public:
GpsAcPusherMock()
: gpsWasSet(false)
{}
virtual void pushGPSCoordinates(sint32 latMs, sint32 longMs)
{
printf("pushGPSCoordinates received: %d and %d\n", latMs, longMs);
gpsWasSet = true;
latitudeMs = latMs;
longitudeMs = longMs;
}
void clear()
{
gpsWasSet = false;
latitudeMs = 0;
longitudeMs = 0;
}
sint32 latitudeMs;
sint32 longitudeMs;
bool gpsWasSet;
};
class GpsConverterTest
{
public:
GpsConverterTest()
: canTransceiverMock()
, converter(canTransceiverMock, acPusherMock)
{}
virtual ~GpsConverterTest() {}
can::CanTransceiverMock canTransceiverMock;
GpsAcPusherMock acPusherMock;
GpsConverter converter;
};
static bool withinTolerance(sint32 x1, sint32 x2, sint32 tolerance)
{
return abs(x1-x2) < tolerance;
}
TEST_CASE_METHOD(GpsConverterTest, "london east calling", "[gps]")
{
uint8 payload[8] = { 0xDF, 0x48, 0xEA, 0xFF, 0x08, 0xC5, 0xA5, 0x24 };
CANFrame gpsInfo(0x34a, payload, 8);
converter.frameReceived(gpsInfo);
CHECK(acPusherMock.gpsWasSet);
CHECK(withinTolerance(acPusherMock.latitudeMs, 185528159, 100));
CHECK(withinTolerance(acPusherMock.longitudeMs, -429429, 100));
}
TEST_CASE_METHOD(GpsConverterTest, "london west calling", "[gps]")
{
uint8 payload[8] = { 0x1F, 0xB7, 0x15, 0x00, 0x08, 0xC5, 0xA5, 0x24 };
CANFrame gpsInfo(0x34a, payload, 8);
converter.frameReceived(gpsInfo);
SECTION("receive once")
{
CHECK(acPusherMock.gpsWasSet);
CHECK(withinTolerance(acPusherMock.latitudeMs, 185528159, 100));
CHECK(withinTolerance(acPusherMock.longitudeMs, 429428, 100));
}
SECTION("receive twice same value, only propagate once")
{
CHECK(acPusherMock.gpsWasSet);
CHECK(withinTolerance(acPusherMock.latitudeMs, 185528159, 100));
CHECK(withinTolerance(acPusherMock.longitudeMs, 429428, 100));
acPusherMock.clear();
converter.frameReceived(gpsInfo);
CHECK(!acPusherMock.gpsWasSet);
}
}
TEST_CASE_METHOD(GpsConverterTest, "invalid data", "[gps]")
{
uint8 payload[8] = { 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 };
CANFrame gpsInfo(0x34a, payload, 8);
converter.frameReceived(gpsInfo);
CHECK(!acPusherMock.gpsWasSet);
}
TEST_CASE_METHOD(GpsConverterTest, "no signal", "[gps]")
{
uint8 payload[8] = { 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F };
CANFrame gpsInfo(0x34a, payload, 8);
converter.frameReceived(gpsInfo);
CHECK(!acPusherMock.gpsWasSet);
}
// 48.1172966,11.5913253
// 48.1173275,11.591452
} // namespace test

9427
2016/ppc/gps/test/catch.hpp Normal file

File diff suppressed because it is too large Load Diff

15
2016/ppc/rakefile.rb Normal file
View File

@ -0,0 +1,15 @@
desc "build"
task :build do
sh "bake -m gps -b UnitTest -a black"
end
desc "run"
task :run => :build do
sh "./gps/build_UnitTest/gpsTests.exe"
end
desc "clean"
task :clean do
sh "bake -m gps -b UnitTest -a black -c"
end