diff --git a/firmware/inc/location.h b/firmware/inc/location.h new file mode 100644 index 0000000..f8133e0 --- /dev/null +++ b/firmware/inc/location.h @@ -0,0 +1,31 @@ +/* + * Location related things + * Copyright (C) 2015 Richard Meadows + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef LOCATION_H +#define LOCATION_H + + +bool latlon_in_aprs_zone(int32_t aprs_zone, int32_t aprs_zone_outline, float lon, float lat); + +#endif /* LOCATION_H */ diff --git a/firmware/src/location.c b/firmware/src/location.c new file mode 100644 index 0000000..05faa18 --- /dev/null +++ b/firmware/src/location.c @@ -0,0 +1,118 @@ +/* + * Location related things + * Copyright (C) 2015 Richard Meadows + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include +#include + +#include "samd20.h" +#include "geofence_aprs.h" + + +#define polyX(i) (poly[(i*2)+0]) +#define polyY(i) (poly[(i*2)+1]) + +/** + * point_in_polygon function from http://alienryderflex.com/polygon/ + * + * The function will return `true` if the point x,y is inside the + * polygon, or `false` if it is not. If the point is exactly on the + * edge of the polygon, then the function may return `true` or + * `false`. + * + * x - longitude + * y - latitude + * + * Note that division by zero is avoided because the division is + * protected by the "if" clause which surrounds it. + */ +bool point_in_polygon(int32_t* poly, uint32_t points, int32_t x, int32_t y) { + + uint32_t i, j = points-1; + bool oddNodes = false; + + for (i = 0; i < points; i++) { + + if (((polyY(i) < y && polyY(j) >= y) || (polyY(j) < y && polyY(i) >= y)) && + (polyX(i) <= x || polyX(j) <= x)) { + + if (polyX(i) + (y-polyY(i)) / (polyY(j) - polyY(i)) * (polyX(j)-polyX(i)) < x) { + oddNodes =! oddNodes; + } + } + + j = i; + } + + return oddNodes; +} +/** + * Returns if a latitude and longitude is in a polygon + */ +bool latlon_in_polygon(int32_t* poly, uint32_t points, float lon, float lat) { + + int32_t x = (int32_t)round(lon * 1000 * 1000); // longitude: µdegrees + int32_t y = (int32_t)round(lat * 1000 * 1000); // latitude: µdegrees + + return point_in_polygon(poly, points, x, y); +} + + + +int32_t current_aprs_zone, current_aprs_zone_outline; + +/** + * Returns if a latitude and longitude is in a given aprs zone outline + */ +bool latlon_in_aprs_zone(int32_t aprs_zone, int32_t aprs_zone_outline, float lon, float lat) { + return latlon_in_polygon( + aprs_zones[aprs_zone].outlines[aprs_zone_outline], + aprs_zones[aprs_zone].outline_lengths[aprs_zone_outline], + lon, lat); +} + +/** + * Updates the aprs location based on the current lat/lon + */ +void update_aprs_location(float lon, float lat) { + + /* Were we in an aprs zone last time? */ + + + if (0) { + + /* Are we still in the same outline? */ + + if (1) { /* Still in outline */ + return; + } + } + + /* Find which aprs zone we are in and save it */ +} + +void aprs_location_init(float lon, float lat) { + current_aprs_zone = -1; current_aprs_zone_outline = -1; + update_aprs_location(lon, lat); +} diff --git a/firmware/test/tc/location_aprs.h b/firmware/test/tc/location_aprs.h new file mode 100644 index 0000000..1a6ca7f --- /dev/null +++ b/firmware/test/tc/location_aprs.h @@ -0,0 +1,20 @@ +#ifndef __verification__ +#define __verification__ +#endif + +/****************************//* location_aprs_tc *//****************************/ +/* Checks the location is returning the right things etc. etc */ + +/* Parameters in */ +struct location_aprs_tc_params { + int input; +} location_aprs_tc_params; +/* Results out */ +struct location_aprs_tc_results { + int result; +} location_aprs_tc_results; +/* Function */ +__verification__ void location_aprs_tc(void) { + + location_aprs_tc_results.result = 2 * location_aprs_tc_params.input; +} diff --git a/firmware/test/tc/location_aprs.py b/firmware/test/tc/location_aprs.py new file mode 100644 index 0000000..e374ebc --- /dev/null +++ b/firmware/test/tc/location_aprs.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# ------------------------------------------------------------------------------ +# Imports +# ------------------------------------------------------------------------------ + +import sys +sys.path.append("./test") +import main + +from random import randint + +# ------------------------------------------------------------------------------ +# Test Script +# ------------------------------------------------------------------------------ + +class location_aprs_tc: + def __init__(self): + self.name = self.__class__.__name__ + self.iterations = 20 + + + def get_test(self): + """Returns some suitable test parameters""" + params = main.struct_location_aprs_tc_params() + params.input = randint(0, 10000) + + return params + + def is_correct(self, params, result, print_info): + """Returns if a result is correct for the given parameters""" + + print_info("%d * 2 = %d"%(params.input, result['result'])) + + if (params.input * 2 == result['result']): + return True + else: + return False