randogoth c4da02ca2c Randonaut Watch Face (#233)
* init

* advanced latlon setting

* simple functionality done

* lat lon high precision fwd bwd

* edit toggle

* added readme for branch

* DD DMS conversion & cleanup

* DD to OLC conversion

* olc encoding & decoding

* OLC implementation

* swapped bools for modes, code cleanup

* place name editor

* updated button logic, fixed display

* load and save  places in state array

* todo list

* simplified OLC functions

* geohash conversion functions

* geohash display & digit functions

* todo

* finished geohash implementation

* code display function, defaults, bugfixes

* read/write file/reg logic

* long light in DATA to cancel

* write to registry

* todo

* read & write backup register

* file read/write

* todo

* new more concise button logic, optimizations

* todo

* renamed & cleaned up, fixed button logic

* documentation

* documentation

* LAP mode for all coordinate screens

* faster and more precise geohash algorithm

* updated description

* updated docu

* simple place face

* bugfixes, updated documentation

* init

* meh

* added public functions for OLC and Geohash

* randonauting face

* fix

* display fix

* cleanup

* bugfixes

* bugfix

* added place

* fixed TRNG call

* fixed declaration conflict

* modulo bias filter

* simplified things, chance RNG selection

* fixed button logic, better menus

* cleanup

* documentation

* docu fixes

* original README

* updated place_face

* fallback to register location

* removed pointless freq req

* reset config

* fixed dependency issue

* minor bugfixes

* saved a bit :)

* fix
2023-04-16 11:00:44 -04:00

232 lines
8.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* MIT License
*
* Copyright (c) 2023 Tobias Raayoni Last / @randogoth
*
* 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 place_FACE_H_
#define place_FACE_H_
#include "movement.h"
/*
* PLACE FACE
* ==========
*
* Based on and expanded from the Sunrise/Sunset face. Outsourced the location setting functionality to
* its own face. Also serves as a converter between different coordinate notation formats.
*
* With the LIGHT button each place coordinate can be shown and edited in 4 different display modes:
*
* 1) Decimal Latitude and Longitude (WGS84) up to 5 decimal points
* 2) Latitude and Longitude (WGS84) in traditional DD°MM'SS" notation
* 3) Ten digit Open Location Code (aka. PlusCode) format
* 4) Ten digit Geohash format
*
* Using the ALARM button the user can flip through 2 pages of coordinate info to see the first and
* second sets of digits.
*
* (please also refer to the notes on precision below)
*
* Editing Mode
* ============
*
* A LONG PRESS of the LIGHT button toggles editing mode for each of the selected notations.
*
* In this mode LIGHT moves the cursor and ALARM changes the letter cycling through the available
* alphabet or numbers.
*
* When OLC or Geohash display are edited, Digit Info mode is activated. It serves as a workaround
* for the limitation of how ambiguously alphanumeric characters are displayed on the main seven segment
* digits of the watch face ( S or 5, I or 1, U or W?).
*
* The selected letter is also shown in the much easier to read alphanumeric 8 segment weekday digit above.
* In addition the '24H' indicator is active when the selected digit represents a number and the 'PM'
* indicator for a letter.
*
* A LONG PRESS of LIGHT saves the changes.
*
* Coordinates are read or stored to both the traditional internal location register and a file on
* the LFS file system ("place.loc"). By default the Watch Face loads the coordinates from file
* when activated. If no file is present, the coordinates are loaded from the register.
* (please also see the notes on precision below)
*
* Auxiliary Mode: Digit Info
* ==========================
*
* A LONG PRESS of the ALARM button toggles Digit Info mode when OLC or Geohash display is active.
* (LAP indicator is on) It is a means of being able to see the detailed Digit Info as described above
* but without the risk of accidentally editing any of digits.
*
* Both ALARM and LIGHT buttons can be used to flip through the letters.
*
* Notes on Coordinate Precision
* =============================
*
* The common WGS84 Latitude and Longitude degrees naturally do not represent meters in distance
* on the ground. 1° Longitude on the equatorial line equals a width of 111.32 kilometers, but
* at 40° latitude further North or South it is approximately 85 kilometers wide. The closer to
* the poles the narrower (and more precise) the latitude degrees get.
*
* The Sensor Watch's traditional 16bit location register only stores latitudes and longitudes
* with two decimal points. That equals a longitudal precision of 36 arc seconds, or ~1111 meters
* at the equator - precise enough for astronomical calculations, but not if you want to store the
* location of let's say a building.
*
* Hence we propose the <place.loc> file that serves the same purpose, but with a precision of
* five decimal digits. That equals 0.04 arc seconds or 1.11 meters at the equator.
*
* Please also note that the different notations of this watch face also have varying magnitudes
* of precision:
*
* | Format | Notation | Precision at Equator | Precision at 67° N/S |
* | ------------------ | ---------------------- | -------------------- | -------------------- |
* | 2d. Decimal LatLon | 29.98, 31.13 | 1111.320 m | 435.125 m |
* | 5d. Decimal LatLon | 29.97916, 31.13417 | 1.111 m | 0.435 m |
* | DMS LatLon | N 29°5845″, E 31°83″ | 30.833 m | 12.083 m |
* | Open Location Code | 7GXHX4HM+MM | 13.875 m | 13.875 m |
* | Geohash | stq4s3x1qu | 1.189 m | 0.596 m |
*
* Since all notations are internally converted into degrees with 5 decimal points, expect some
* rounding errors when editing or loading the coordinates in other notation formats.
*
*/
static const char olc_alphabet[20] = "23456789CFGHJMPQRUWX";
static const char geohash_alphabet[32] = "0123456789bCdEfGhjkmnpqrstuVwxyz";
typedef struct {
uint8_t sign: 1; // 0-1
uint8_t hundreds: 1; // 0-1
uint8_t tens: 4; // 0-9
uint8_t ones: 4; // 0-9
uint8_t d01: 4; // 0-9
uint8_t d02: 4; // 0-9
uint8_t d03: 4; // 0-9
uint8_t d04: 4; // 0-9
uint8_t d05: 4; // 0-9
} place_format_decimal_latlon_t;
typedef struct {
uint8_t sign: 1; // 0-1
uint8_t hundreds: 1; // 0-1
uint8_t tens: 4; // 0-9
uint8_t ones: 4; // 0-9
uint8_t mins_tens: 3; // 0-5
uint8_t mins_ones: 4; // 0-9
uint8_t secs_tens: 3; // 0-5
uint8_t secs_ones: 4; // 0-9
} place_format_dms_latlon_t;
typedef struct {
uint8_t lat1: 5; // 2-X
uint8_t lon1: 5; // 2-X
uint8_t lat2: 5; // 2-X
uint8_t lon2: 5; // 2-X
uint8_t lat3: 5; // 2-X
uint8_t lon3: 5; // 2-X
uint8_t lat4: 5; // 2-X
uint8_t lon4: 5; // 2-X
uint8_t lat5: 5; // 2-X
uint8_t lon5: 5; // 2-X
} place_format_olc_t;
typedef struct {
int32_t latitude : 25;
int32_t longitude : 26;
} coordinate_t;
typedef struct {
place_format_decimal_latlon_t latitude;
place_format_decimal_latlon_t longitude;
} place_coordinate_t;
typedef struct {
uint8_t d01: 6; // 0-z
uint8_t d02: 6; // 0-z
uint8_t d03: 6; // 0-z
uint8_t d04: 6; // 0-z
uint8_t d05: 6; // 0-z
uint8_t d06: 6; // 0-z
uint8_t d07: 6; // 0-z
uint8_t d08: 6; // 0-z
uint8_t d09: 6; // 0-z
uint8_t d10: 6; // 0-z
} place_format_geohash_t;
typedef struct {
double max;
double min;
} place_format_geohash_interval;
typedef struct {
uint8_t min_digit : 1;
uint8_t max_digit : 3;
} place_mode_schema_page_t;
typedef struct {
uint8_t max_page : 3;
place_mode_schema_page_t page[4];
} place_mode_schema_mode_t;
enum place_modes_e {
MODE_DECIMAL = 0,
MODE_DMS,
MODE_OLC,
MODE_GEOHASH
};
typedef struct {
enum place_modes_e mode;
uint8_t page : 3;
int8_t active_digit: 4;
bool edit;
bool digit_info;
place_format_decimal_latlon_t working_latitude;
place_format_decimal_latlon_t working_longitude;
place_format_dms_latlon_t working_dms_latitude;
place_format_dms_latlon_t working_dms_longitude;
place_format_olc_t working_pluscode;
place_format_geohash_t working_geohash;
place_mode_schema_mode_t modes[4];
} place_state_t;
// PUBLIC WATCH FACE FUNCTIONS ////////////////////////////////////////////////
void place_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
void place_face_activate(movement_settings_t *settings, void *context);
bool place_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
void place_face_resign(movement_settings_t *settings, void *context);
void place_latlon_to_olc(char *pluscode, double latitude, double longitude);
void place_latlon_to_geohash(char *geohash, double latitude, double longitude);
#define place_face ((const watch_face_t){ \
place_face_setup, \
place_face_activate, \
place_face_loop, \
place_face_resign, \
NULL, \
})
#endif // place_FACE_H_