mirror of
https://github.com/firewalkwithm3/Sensor-Watch.git
synced 2024-11-22 19:20:30 +08:00
Merge branch 'main' of github.com:joeycastillo/Sensor-Watch into motion-express
This commit is contained in:
commit
cd40573535
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
|
@ -13,7 +13,9 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
- name: Work around CVE-2022-24765
|
||||||
|
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
- name: Compile starter-project app
|
- name: Compile starter-project app
|
||||||
run: make
|
run: make
|
||||||
working-directory: 'apps/starter-project'
|
working-directory: 'apps/starter-project'
|
||||||
|
@ -35,7 +37,9 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
- name: Work around CVE-2022-24765
|
||||||
|
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
- name: Compile movement
|
- name: Compile movement
|
||||||
run: emmake make
|
run: emmake make
|
||||||
working-directory: 'movement/make'
|
working-directory: 'movement/make'
|
||||||
|
|
2
Doxyfile
2
Doxyfile
|
@ -5,7 +5,7 @@
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
DOXYFILE_ENCODING = UTF-8
|
DOXYFILE_ENCODING = UTF-8
|
||||||
PROJECT_NAME = "Sensor Watch"
|
PROJECT_NAME = "Sensor Watch"
|
||||||
PROJECT_NUMBER = "0.0.0"
|
PROJECT_NUMBER = "0.0.1"
|
||||||
PROJECT_BRIEF = "A board replacement for the classic Casio F-91W wristwatch, powered by a Microchip SAM L22 microcontroller."
|
PROJECT_BRIEF = "A board replacement for the classic Casio F-91W wristwatch, powered by a Microchip SAM L22 microcontroller."
|
||||||
PROJECT_LOGO =
|
PROJECT_LOGO =
|
||||||
OUTPUT_DIRECTORY = "."
|
OUTPUT_DIRECTORY = "."
|
||||||
|
|
|
@ -3302,6 +3302,10 @@ Please make sure your boards conform to these design rules.
|
||||||
<via x="19.4056" y="7.4803" extent="1-16" drill="0.3048"/>
|
<via x="19.4056" y="7.4803" extent="1-16" drill="0.3048"/>
|
||||||
<via x="19.9136" y="5.1943" extent="1-16" drill="0.3048"/>
|
<via x="19.9136" y="5.1943" extent="1-16" drill="0.3048"/>
|
||||||
<via x="17.907" y="10.2235" extent="1-16" drill="0.3048"/>
|
<via x="17.907" y="10.2235" extent="1-16" drill="0.3048"/>
|
||||||
|
<wire x1="13.492" y1="22.836440625" x2="13.492" y2="21.4249" width="0.254" layer="1"/>
|
||||||
|
<wire x1="13.492" y1="21.4249" x2="13.2334" y2="21.4249" width="0.254" layer="1"/>
|
||||||
|
<wire x1="13.2334" y1="21.4249" x2="13.1826" y2="21.3741" width="0.254" layer="1"/>
|
||||||
|
<wire x1="13.1826" y1="21.3741" x2="13.1826" y2="21.2725" width="0.254" layer="1"/>
|
||||||
</signal>
|
</signal>
|
||||||
<signal name="!RESET">
|
<signal name="!RESET">
|
||||||
<contactref element="!RST" pad="P$1"/>
|
<contactref element="!RST" pad="P$1"/>
|
||||||
|
|
10
apps/uart-display/Makefile
Executable file
10
apps/uart-display/Makefile
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
TOP = ../..
|
||||||
|
include $(TOP)/make.mk
|
||||||
|
|
||||||
|
INCLUDES += \
|
||||||
|
-I./
|
||||||
|
|
||||||
|
SRCS += \
|
||||||
|
./app.c
|
||||||
|
|
||||||
|
include $(TOP)/rules.mk
|
104
apps/uart-display/app.c
Normal file
104
apps/uart-display/app.c
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <peripheral_clk_config.h>
|
||||||
|
#include "watch.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Beginnings of a program to take UART input and update the screen accordingly.
|
||||||
|
Use alongside a prpgram that communicates with the watch over the UART pins.
|
||||||
|
This CircuitPython script turns the LED red in response to pressing the LIGHT button,
|
||||||
|
and turns it off when the MODE button is pressed:
|
||||||
|
|
||||||
|
```
|
||||||
|
import board
|
||||||
|
import busio
|
||||||
|
|
||||||
|
uart = busio.UART(board.TX, board.RX, baudrate=19200)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
uart.write(b"\x00")
|
||||||
|
data = uart.read(1)
|
||||||
|
|
||||||
|
if data is not None:
|
||||||
|
data_string = ''.join([chr(b) for b in data])
|
||||||
|
print(data_string, end="")
|
||||||
|
if data_string[0] == 'L':
|
||||||
|
uart.write(b"R")
|
||||||
|
elif data_string[0] == 'M':
|
||||||
|
uart.write(b"O")
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
char button_pressed = 0;
|
||||||
|
|
||||||
|
static void cb_light_pressed(void) {
|
||||||
|
button_pressed = 'L';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cb_mode_pressed(void) {
|
||||||
|
button_pressed = 'M';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cb_alarm_pressed(void) {
|
||||||
|
button_pressed = 'A';
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_init(void) {
|
||||||
|
watch_enable_leds();
|
||||||
|
watch_enable_buzzer();
|
||||||
|
|
||||||
|
watch_enable_external_interrupts();
|
||||||
|
watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_RISING);
|
||||||
|
watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_RISING);
|
||||||
|
watch_register_interrupt_callback(BTN_ALARM, cb_alarm_pressed, INTERRUPT_TRIGGER_RISING);
|
||||||
|
|
||||||
|
watch_enable_display();
|
||||||
|
|
||||||
|
watch_enable_uart(A2, A1, 19200);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_wake_from_backup(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_setup(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_prepare_for_standby(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_wake_from_standby(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool app_loop(void) {
|
||||||
|
char buf[3];
|
||||||
|
|
||||||
|
if (button_pressed) {
|
||||||
|
sprintf(buf, "%c", button_pressed);
|
||||||
|
printf("%s\n", buf);
|
||||||
|
watch_uart_puts(buf);
|
||||||
|
button_pressed = 0;
|
||||||
|
}
|
||||||
|
char char_received = watch_uart_getc();
|
||||||
|
if (char_received) {
|
||||||
|
switch (char_received) {
|
||||||
|
case 'R':
|
||||||
|
watch_set_led_red();
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
watch_set_led_green();
|
||||||
|
break;
|
||||||
|
case 'Y':
|
||||||
|
watch_set_led_yellow();
|
||||||
|
break;
|
||||||
|
case 'O':
|
||||||
|
watch_set_led_off();
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
// receive a display update?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
8
make.mk
8
make.mk
|
@ -3,7 +3,7 @@ BUILD = ./build
|
||||||
BIN = watch
|
BIN = watch
|
||||||
|
|
||||||
ifndef BOARD
|
ifndef BOARD
|
||||||
override BOARD = OSO-SWAT-A1-04
|
override BOARD = OSO-SWAT-A1-05
|
||||||
endif
|
endif
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
@ -161,6 +161,7 @@ SRCS += \
|
||||||
$(TOP)/watch-library/simulator/watch/watch_deepsleep.c \
|
$(TOP)/watch-library/simulator/watch/watch_deepsleep.c \
|
||||||
$(TOP)/watch-library/simulator/watch/watch_private.c \
|
$(TOP)/watch-library/simulator/watch/watch_private.c \
|
||||||
$(TOP)/watch-library/simulator/watch/watch.c \
|
$(TOP)/watch-library/simulator/watch/watch.c \
|
||||||
|
$(TOP)/watch-library/shared/driver/thermistor_driver.c \
|
||||||
$(TOP)/watch-library/shared/watch/watch_private_buzzer.c \
|
$(TOP)/watch-library/shared/watch/watch_private_buzzer.c \
|
||||||
$(TOP)/watch-library/shared/watch/watch_private_display.c \
|
$(TOP)/watch-library/shared/watch/watch_private_display.c \
|
||||||
$(TOP)/watch-library/shared/watch/watch_utility.c \
|
$(TOP)/watch-library/shared/watch/watch_utility.c \
|
||||||
|
@ -171,6 +172,11 @@ ifeq ($(LED), BLUE)
|
||||||
CFLAGS += -DWATCH_SWAP_LED_PINS
|
CFLAGS += -DWATCH_SWAP_LED_PINS
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef FIRMWARE
|
||||||
|
CFLAGS += -DMOVEMENT_FIRMWARE_$(FIRMWARE)=1
|
||||||
|
CFLAGS += -DMOVEMENT_FIRMWARE=MOVEMENT_FIRMWARE_$(FIRMWARE)
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(BOARD), OSO-FEAL-A1-00)
|
ifeq ($(BOARD), OSO-FEAL-A1-00)
|
||||||
CFLAGS += -DCRYSTALLESS
|
CFLAGS += -DCRYSTALLESS
|
||||||
endif
|
endif
|
||||||
|
|
41
movement/alt_fw/alt_time.h
Normal file
41
movement/alt_fw/alt_time.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 MOVEMENT_CONFIG_H_
|
||||||
|
#define MOVEMENT_CONFIG_H_
|
||||||
|
|
||||||
|
#include "movement_faces.h"
|
||||||
|
|
||||||
|
const watch_face_t watch_faces[] = {
|
||||||
|
simple_clock_face,
|
||||||
|
beats_face,
|
||||||
|
day_one_face,
|
||||||
|
|
||||||
|
preferences_face,
|
||||||
|
set_time_face,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MOVEMENT_NUM_FACES (sizeof(watch_faces) / sizeof(watch_face_t))
|
||||||
|
|
||||||
|
#endif // MOVEMENT_CONFIG_H_
|
61
movement/alt_fw/deep_space_now.h
Normal file
61
movement/alt_fw/deep_space_now.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 MOVEMENT_CONFIG_H_
|
||||||
|
#define MOVEMENT_CONFIG_H_
|
||||||
|
|
||||||
|
#include "movement_faces.h"
|
||||||
|
|
||||||
|
// Preset Goldstone (GO), Madrid (MA), and Canberra (CA) time zones.
|
||||||
|
// Also prepopulate the Day One register with Voyager 1's launch (September 5, 1977)
|
||||||
|
|
||||||
|
#define MOVEMENT_CUSTOM_BOOT_COMMANDS() { \
|
||||||
|
/* Standard Time */\
|
||||||
|
/*\
|
||||||
|
watch_store_backup_data(0x1e0c0c, 4);\
|
||||||
|
watch_store_backup_data(0x010115, 5);\
|
||||||
|
watch_store_backup_data(0x130105, 6);\
|
||||||
|
*/\
|
||||||
|
/* Daylight Saving Time */\
|
||||||
|
watch_store_backup_data(0x1f0c0c, 4);\
|
||||||
|
watch_store_backup_data(0x020115, 5);\
|
||||||
|
watch_store_backup_data(0x110105, 6);\
|
||||||
|
watch_store_backup_data(0x0597b9, 2);\
|
||||||
|
}
|
||||||
|
|
||||||
|
const watch_face_t watch_faces[] = {
|
||||||
|
simple_clock_face,
|
||||||
|
mars_time_face,
|
||||||
|
world_clock_face,
|
||||||
|
world_clock_face,
|
||||||
|
world_clock_face,
|
||||||
|
day_one_face,
|
||||||
|
|
||||||
|
preferences_face,
|
||||||
|
set_time_face,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MOVEMENT_NUM_FACES (sizeof(watch_faces) / sizeof(watch_face_t))
|
||||||
|
|
||||||
|
#endif // MOVEMENT_CONFIG_H_
|
42
movement/alt_fw/focus.h
Normal file
42
movement/alt_fw/focus.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 MOVEMENT_CONFIG_H_
|
||||||
|
#define MOVEMENT_CONFIG_H_
|
||||||
|
|
||||||
|
#include "movement_faces.h"
|
||||||
|
|
||||||
|
const watch_face_t watch_faces[] = {
|
||||||
|
simple_clock_face,
|
||||||
|
tomato_face,
|
||||||
|
stopwatch_face,
|
||||||
|
countdown_face,
|
||||||
|
|
||||||
|
preferences_face,
|
||||||
|
set_time_face,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MOVEMENT_NUM_FACES (sizeof(watch_faces) / sizeof(watch_face_t))
|
||||||
|
|
||||||
|
#endif // MOVEMENT_CONFIG_H_
|
43
movement/alt_fw/standard.h
Normal file
43
movement/alt_fw/standard.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 MOVEMENT_CONFIG_H_
|
||||||
|
#define MOVEMENT_CONFIG_H_
|
||||||
|
|
||||||
|
#include "movement_faces.h"
|
||||||
|
|
||||||
|
const watch_face_t watch_faces[] = {
|
||||||
|
simple_clock_face,
|
||||||
|
world_clock_face,
|
||||||
|
sunrise_sunset_face,
|
||||||
|
moon_phase_face,
|
||||||
|
thermistor_readout_face,
|
||||||
|
|
||||||
|
preferences_face,
|
||||||
|
set_time_face,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MOVEMENT_NUM_FACES (sizeof(watch_faces) / sizeof(watch_face_t))
|
||||||
|
|
||||||
|
#endif // MOVEMENT_CONFIG_H_
|
43
movement/alt_fw/the_athlete.h
Normal file
43
movement/alt_fw/the_athlete.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 MOVEMENT_CONFIG_H_
|
||||||
|
#define MOVEMENT_CONFIG_H_
|
||||||
|
|
||||||
|
#include "movement_faces.h"
|
||||||
|
|
||||||
|
const watch_face_t watch_faces[] = {
|
||||||
|
simple_clock_face,
|
||||||
|
stopwatch_face,
|
||||||
|
countdown_face,
|
||||||
|
counter_face,
|
||||||
|
pulsometer_face,
|
||||||
|
|
||||||
|
preferences_face,
|
||||||
|
set_time_face,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MOVEMENT_NUM_FACES (sizeof(watch_faces) / sizeof(watch_face_t))
|
||||||
|
|
||||||
|
#endif // MOVEMENT_CONFIG_H_
|
44
movement/alt_fw/the_backpacker.h
Normal file
44
movement/alt_fw/the_backpacker.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 MOVEMENT_CONFIG_H_
|
||||||
|
#define MOVEMENT_CONFIG_H_
|
||||||
|
|
||||||
|
#include "movement_faces.h"
|
||||||
|
|
||||||
|
const watch_face_t watch_faces[] = {
|
||||||
|
simple_clock_face,
|
||||||
|
sunrise_sunset_face,
|
||||||
|
moon_phase_face,
|
||||||
|
thermistor_readout_face,
|
||||||
|
thermistor_logging_face,
|
||||||
|
blinky_face,
|
||||||
|
|
||||||
|
preferences_face,
|
||||||
|
set_time_face,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MOVEMENT_NUM_FACES (sizeof(watch_faces) / sizeof(watch_face_t))
|
||||||
|
|
||||||
|
#endif // MOVEMENT_CONFIG_H_
|
48
movement/alt_fw/the_stargazer.h
Normal file
48
movement/alt_fw/the_stargazer.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 MOVEMENT_CONFIG_H_
|
||||||
|
#define MOVEMENT_CONFIG_H_
|
||||||
|
|
||||||
|
#include "movement_faces.h"
|
||||||
|
|
||||||
|
#define MOVEMENT_CUSTOM_BOOT_COMMANDS() { \
|
||||||
|
movement_state.settings.bit.led_green_color = 0x0;\
|
||||||
|
movement_state.settings.bit.led_red_color = 0xF;\
|
||||||
|
watch_store_backup_data(movement_state.settings.reg, 0);\
|
||||||
|
}
|
||||||
|
|
||||||
|
const watch_face_t watch_faces[] = {
|
||||||
|
simple_clock_face,
|
||||||
|
astronomy_face,
|
||||||
|
sunrise_sunset_face,
|
||||||
|
moon_phase_face,
|
||||||
|
|
||||||
|
preferences_face,
|
||||||
|
set_time_face,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MOVEMENT_NUM_FACES (sizeof(watch_faces) / sizeof(watch_face_t))
|
||||||
|
|
||||||
|
#endif // MOVEMENT_CONFIG_H_
|
|
@ -84,7 +84,7 @@ static void addUncounted(uint8_t data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(uint8_t data) {
|
static void __write(uint8_t data) {
|
||||||
++byteCount;
|
++byteCount;
|
||||||
addUncounted(data);
|
addUncounted(data);
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ void write(uint8_t data) {
|
||||||
|
|
||||||
void writeArray(uint8_t *buffer, uint8_t size){
|
void writeArray(uint8_t *buffer, uint8_t size){
|
||||||
while (size--) {
|
while (size--) {
|
||||||
write(*buffer++);
|
__write(*buffer++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ void initHmac(const uint8_t* key, uint8_t keyLength) {
|
||||||
if (keyLength > BLOCK_LENGTH) {
|
if (keyLength > BLOCK_LENGTH) {
|
||||||
// Hash long keys
|
// Hash long keys
|
||||||
init();
|
init();
|
||||||
for (;keyLength--;) write(*key++);
|
for (;keyLength--;) __write(*key++);
|
||||||
memcpy(keyBuffer,result(),HASH_LENGTH);
|
memcpy(keyBuffer,result(),HASH_LENGTH);
|
||||||
} else {
|
} else {
|
||||||
// Block length keys are used as is
|
// Block length keys are used as is
|
||||||
|
@ -153,7 +153,7 @@ void initHmac(const uint8_t* key, uint8_t keyLength) {
|
||||||
// Start inner hash
|
// Start inner hash
|
||||||
init();
|
init();
|
||||||
for (i=0; i<BLOCK_LENGTH; i++) {
|
for (i=0; i<BLOCK_LENGTH; i++) {
|
||||||
write(keyBuffer[i] ^ HMAC_IPAD);
|
__write(keyBuffer[i] ^ HMAC_IPAD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ uint8_t* resultHmac(void) {
|
||||||
memcpy(innerHash,result(),HASH_LENGTH);
|
memcpy(innerHash,result(),HASH_LENGTH);
|
||||||
// Calculate outer hash
|
// Calculate outer hash
|
||||||
init();
|
init();
|
||||||
for (i=0; i<BLOCK_LENGTH; i++) write(keyBuffer[i] ^ HMAC_OPAD);
|
for (i=0; i<BLOCK_LENGTH; i++) __write(keyBuffer[i] ^ HMAC_OPAD);
|
||||||
for (i=0; i<HASH_LENGTH; i++) write(innerHash[i]);
|
for (i=0; i<HASH_LENGTH; i++) __write(innerHash[i]);
|
||||||
return result();
|
return result();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ void init(void);
|
||||||
void initHmac(const uint8_t* secret, uint8_t secretLength);
|
void initHmac(const uint8_t* secret, uint8_t secretLength);
|
||||||
uint8_t* result(void);
|
uint8_t* result(void);
|
||||||
uint8_t* resultHmac(void);
|
uint8_t* resultHmac(void);
|
||||||
void write(uint8_t);
|
|
||||||
void writeArray(uint8_t *buffer, uint8_t size);
|
void writeArray(uint8_t *buffer, uint8_t size);
|
||||||
|
|
||||||
#endif // SHA1_H
|
#endif // SHA1_H
|
||||||
|
|
9
movement/lib/astrolib/LICENSE.txt
Executable file
9
movement/lib/astrolib/LICENSE.txt
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
Public domain
|
||||||
|
|
||||||
|
THIS 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.
|
9
movement/lib/astrolib/README.md
Normal file
9
movement/lib/astrolib/README.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Astrolib
|
||||||
|
|
||||||
|
This is a relatively straightforward C port of Greg Miller's [JavaScript astro library](https://github.com/gmiller123456/astrogreg), done by Joey Castillo, for the Sensor Watch Astronomy watch face.
|
||||||
|
|
||||||
|
He released his work into the public domain and so I release this into the public domain as well.
|
||||||
|
|
||||||
|
I have tested the output of this library against [NASA's Horizons system](https://ssd.jpl.nasa.gov/horizons/app.html#/) and found the results to match (within reason, as we're using a truncated version of VSOP87). Moon calculations still seem a bit iffy, but it doesn't surprise me seeing as there are three calculations involved and the error could stack up.
|
||||||
|
|
||||||
|
THIS 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.
|
555
movement/lib/astrolib/astrolib.c
Normal file
555
movement/lib/astrolib/astrolib.c
Normal file
|
@ -0,0 +1,555 @@
|
||||||
|
/*
|
||||||
|
* Partial C port of Greg Miller's public domain astro library (gmiller@gregmiller.net) 2019
|
||||||
|
* https://github.com/gmiller123456/astrogreg
|
||||||
|
*
|
||||||
|
* Ported by Joey Castillo for Sensor Watch
|
||||||
|
* https://github.com/joeycastillo/Sensor-Watch/
|
||||||
|
*
|
||||||
|
* Public Domain
|
||||||
|
*
|
||||||
|
* THIS 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 <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "astrolib.h"
|
||||||
|
#include "vsop87a_milli.h"
|
||||||
|
|
||||||
|
double astro_convert_utc_to_tt(double jd) ;
|
||||||
|
double astro_get_GMST(double ut1);
|
||||||
|
astro_cartesian_coordinates_t astro_subtract_cartesian(astro_cartesian_coordinates_t a, astro_cartesian_coordinates_t b);
|
||||||
|
astro_cartesian_coordinates_t astro_rotate_from_vsop_to_J2000(astro_cartesian_coordinates_t c);
|
||||||
|
astro_matrix_t astro_get_x_rotation_matrix(double r);
|
||||||
|
astro_matrix_t astro_get_y_rotation_matrix(double r);
|
||||||
|
astro_matrix_t astro_get_z_rotation_matrix(double r);
|
||||||
|
astro_matrix_t astro_transpose_matrix(astro_matrix_t m);
|
||||||
|
astro_matrix_t astro_dot_product(astro_matrix_t a, astro_matrix_t b);
|
||||||
|
astro_matrix_t astro_get_precession_matrix(double jd);
|
||||||
|
astro_cartesian_coordinates_t astro_matrix_multiply(astro_cartesian_coordinates_t v, astro_matrix_t m);
|
||||||
|
astro_cartesian_coordinates_t astro_convert_geodedic_latlon_to_ITRF_XYZ(double lat, double lon, double height);
|
||||||
|
astro_cartesian_coordinates_t astro_convert_ITRF_to_GCRS(astro_cartesian_coordinates_t r, double ut1);
|
||||||
|
astro_cartesian_coordinates_t astro_convert_coordinates_from_meters_to_AU(astro_cartesian_coordinates_t c);
|
||||||
|
astro_cartesian_coordinates_t astro_get_observer_geocentric_coords(double jd, double lat, double lon);
|
||||||
|
astro_cartesian_coordinates_t astro_get_body_coordinates(astro_body_t bodyNum, double et);
|
||||||
|
astro_cartesian_coordinates_t astro_get_body_coordinates_light_time_adjusted(astro_body_t body, astro_cartesian_coordinates_t origin, double t);
|
||||||
|
astro_equatorial_coordinates_t astro_convert_cartesian_to_polar(astro_cartesian_coordinates_t xyz);
|
||||||
|
|
||||||
|
//Special "Math.floor()" function used by convertDateToJulianDate()
|
||||||
|
static double _astro_special_floor(double d) {
|
||||||
|
if(d > 0) {
|
||||||
|
return floor(d);
|
||||||
|
}
|
||||||
|
return floor(d) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double astro_convert_date_to_julian_date(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
|
||||||
|
if (month < 3){
|
||||||
|
year = year - 1;
|
||||||
|
month = month + 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
double b = 0;
|
||||||
|
if (!(year < 1582 || (year == 1582 && (month < 10 || (month == 10 && day < 5))))) {
|
||||||
|
double a = _astro_special_floor(year / 100.0);
|
||||||
|
b = 2 - a + _astro_special_floor(a / 4.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double jd = _astro_special_floor(365.25 * (year + 4716)) + _astro_special_floor(30.6001 * (month + 1)) + day + b - 1524.5;
|
||||||
|
jd += hour / 24.0;
|
||||||
|
jd += minute / 24.0 / 60.0;
|
||||||
|
jd += second / 24.0 / 60.0 / 60.0;
|
||||||
|
|
||||||
|
return jd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return all values in radians.
|
||||||
|
//The positions are adjusted for the parallax of the Earth, and the offset of the observer from the Earth's center
|
||||||
|
//All input and output angles are in radians!
|
||||||
|
astro_equatorial_coordinates_t astro_get_ra_dec(double jd, astro_body_t body, double lat, double lon, bool calculate_precession) {
|
||||||
|
double jdTT = astro_convert_utc_to_tt(jd);
|
||||||
|
double t = astro_convert_jd_to_julian_millenia_since_j2000(jdTT);
|
||||||
|
|
||||||
|
// Get current position of Earth and the target body
|
||||||
|
astro_cartesian_coordinates_t earth_coords = astro_get_body_coordinates(ASTRO_BODY_EARTH, t);
|
||||||
|
astro_cartesian_coordinates_t body_coords = astro_get_body_coordinates_light_time_adjusted(body, earth_coords, t);
|
||||||
|
|
||||||
|
// Convert to Geocentric coordinate
|
||||||
|
body_coords = astro_subtract_cartesian(body_coords, earth_coords);
|
||||||
|
|
||||||
|
//Rotate ecliptic coordinates to J2000 coordinates
|
||||||
|
body_coords = astro_rotate_from_vsop_to_J2000(body_coords);
|
||||||
|
|
||||||
|
astro_matrix_t precession;
|
||||||
|
// TODO: rotate body for precession, nutation and bias
|
||||||
|
if(calculate_precession) {
|
||||||
|
precession = astro_get_precession_matrix(jdTT);
|
||||||
|
body_coords = astro_matrix_multiply(body_coords, precession);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert to topocentric
|
||||||
|
astro_cartesian_coordinates_t observerXYZ = astro_get_observer_geocentric_coords(jdTT, lat, lon);
|
||||||
|
|
||||||
|
if(calculate_precession) {
|
||||||
|
//TODO: rotate observerXYZ for precession, nutation and bias
|
||||||
|
astro_matrix_t precessionInv = astro_transpose_matrix(precession);
|
||||||
|
observerXYZ = astro_matrix_multiply(observerXYZ, precessionInv);
|
||||||
|
}
|
||||||
|
|
||||||
|
body_coords = astro_subtract_cartesian(body_coords, observerXYZ);
|
||||||
|
|
||||||
|
//Convert to topocentric RA DEC by converting from cartesian coordinates to polar coordinates
|
||||||
|
astro_equatorial_coordinates_t retval = astro_convert_cartesian_to_polar(body_coords);
|
||||||
|
|
||||||
|
retval.declination = M_PI/2.0 - retval.declination; //Dec. Offset to make 0 the equator, and the poles +/-90 deg
|
||||||
|
if(retval.right_ascension < 0) retval.right_ascension += 2*M_PI; //Ensure RA is positive
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Converts a Julian Date in UTC to Terrestrial Time (TT)
|
||||||
|
double astro_convert_utc_to_tt(double jd) {
|
||||||
|
//Leap seconds are hard coded, should be updated from the IERS website for other times
|
||||||
|
|
||||||
|
//TAI = UTC + leap seconds (e.g. 32)
|
||||||
|
//TT=TAI + 32.184
|
||||||
|
|
||||||
|
//return jd + (32.0 + 32.184) / 24.0 / 60.0 / 60.0;
|
||||||
|
return jd + (37.0 + 32.184) / 24.0 / 60.0 / 60.0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://data.iana.org/time-zones/tzdb-2018a/leap-seconds.list
|
||||||
|
2272060800 10 # 1 Jan 1972
|
||||||
|
2287785600 11 # 1 Jul 1972
|
||||||
|
2303683200 12 # 1 Jan 1973
|
||||||
|
2335219200 13 # 1 Jan 1974
|
||||||
|
2366755200 14 # 1 Jan 1975
|
||||||
|
2398291200 15 # 1 Jan 1976
|
||||||
|
2429913600 16 # 1 Jan 1977
|
||||||
|
2461449600 17 # 1 Jan 1978
|
||||||
|
2492985600 18 # 1 Jan 1979
|
||||||
|
2524521600 19 # 1 Jan 1980
|
||||||
|
2571782400 20 # 1 Jul 1981
|
||||||
|
2603318400 21 # 1 Jul 1982
|
||||||
|
2634854400 22 # 1 Jul 1983
|
||||||
|
2698012800 23 # 1 Jul 1985
|
||||||
|
2776982400 24 # 1 Jan 1988
|
||||||
|
2840140800 25 # 1 Jan 1990
|
||||||
|
2871676800 26 # 1 Jan 1991
|
||||||
|
2918937600 27 # 1 Jul 1992
|
||||||
|
2950473600 28 # 1 Jul 1993
|
||||||
|
2982009600 29 # 1 Jul 1994
|
||||||
|
3029443200 30 # 1 Jan 1996
|
||||||
|
3076704000 31 # 1 Jul 1997
|
||||||
|
3124137600 32 # 1 Jan 1999
|
||||||
|
3345062400 33 # 1 Jan 2006
|
||||||
|
3439756800 34 # 1 Jan 2009
|
||||||
|
3550089600 35 # 1 Jul 2012
|
||||||
|
3644697600 36 # 1 Jul 2015
|
||||||
|
3692217600 37 # 1 Jan 2017
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
double astro_convert_jd_to_julian_millenia_since_j2000(double jd) {
|
||||||
|
return (jd - 2451545.0) / 365250.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_cartesian_coordinates_t astro_subtract_cartesian(astro_cartesian_coordinates_t a, astro_cartesian_coordinates_t b) {
|
||||||
|
astro_cartesian_coordinates_t retval;
|
||||||
|
|
||||||
|
retval.x = a.x - b.x;
|
||||||
|
retval.y = a.y - b.y;
|
||||||
|
retval.z = a.z - b.z;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performs the rotation from ecliptic coordinates to J2000 coordinates for the given vector x
|
||||||
|
astro_cartesian_coordinates_t astro_rotate_from_vsop_to_J2000(astro_cartesian_coordinates_t c) {
|
||||||
|
/* From VSOP87.doc
|
||||||
|
X +1.000000000000 +0.000000440360 -0.000000190919 X
|
||||||
|
Y = -0.000000479966 +0.917482137087 -0.397776982902 Y
|
||||||
|
Z FK5 0.000000000000 +0.397776982902 +0.917482137087 Z VSOP87A
|
||||||
|
*/
|
||||||
|
astro_cartesian_coordinates_t t;
|
||||||
|
t.x = c.x + c.y * 0.000000440360 + c.z * -0.000000190919;
|
||||||
|
t.y = c.x * -0.000000479966 + c.y * 0.917482137087 + c.z * -0.397776982902;
|
||||||
|
t.z = c.y * 0.397776982902 + c.z * 0.917482137087;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
double astro_get_GMST(double ut1) {
|
||||||
|
double D = ut1 - 2451545.0;
|
||||||
|
double T = D/36525.0;
|
||||||
|
double gmst = fmod((280.46061837 + 360.98564736629*D + 0.000387933*T*T - T*T*T/38710000.0), 360.0);
|
||||||
|
|
||||||
|
if(gmst<0) {
|
||||||
|
gmst+=360;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gmst/15;
|
||||||
|
}
|
||||||
|
|
||||||
|
static astro_matrix_t _astro_get_empty_matrix() {
|
||||||
|
astro_matrix_t t;
|
||||||
|
for(uint8_t i = 0; i < 3 ; i++) {
|
||||||
|
for(uint8_t j = 0 ; j < 3 ; j++) {
|
||||||
|
t.elements[i][j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Gets a rotation matrix about the x axis. Angle R is in radians
|
||||||
|
astro_matrix_t astro_get_x_rotation_matrix(double r) {
|
||||||
|
astro_matrix_t t = _astro_get_empty_matrix();
|
||||||
|
|
||||||
|
t.elements[0][0]=1;
|
||||||
|
t.elements[0][1]=0;
|
||||||
|
t.elements[0][2]=0;
|
||||||
|
t.elements[1][0]=0;
|
||||||
|
t.elements[1][1]=cos(r);
|
||||||
|
t.elements[1][2]=sin(r);
|
||||||
|
t.elements[2][0]=0;
|
||||||
|
t.elements[2][1]=-sin(r);
|
||||||
|
t.elements[2][2]=cos(r);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Gets a rotation matrix about the y axis. Angle R is in radians
|
||||||
|
astro_matrix_t astro_get_y_rotation_matrix(double r) {
|
||||||
|
astro_matrix_t t = _astro_get_empty_matrix();
|
||||||
|
|
||||||
|
t.elements[0][0]=cos(r);
|
||||||
|
t.elements[0][1]=0;
|
||||||
|
t.elements[0][2]=-sin(r);
|
||||||
|
t.elements[1][0]=0;
|
||||||
|
t.elements[1][1]=1;
|
||||||
|
t.elements[1][2]=0;
|
||||||
|
t.elements[2][0]=sin(r);
|
||||||
|
t.elements[2][1]=0;
|
||||||
|
t.elements[2][2]=cos(r);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Gets a rotation matrix about the z axis. Angle R is in radians
|
||||||
|
astro_matrix_t astro_get_z_rotation_matrix(double r) {
|
||||||
|
astro_matrix_t t = _astro_get_empty_matrix();
|
||||||
|
|
||||||
|
t.elements[0][0]=cos(r);
|
||||||
|
t.elements[0][1]=sin(r);
|
||||||
|
t.elements[0][2]=0;
|
||||||
|
t.elements[1][0]=-sin(r);
|
||||||
|
t.elements[1][1]=cos(r);
|
||||||
|
t.elements[1][2]=0;
|
||||||
|
t.elements[2][0]=0;
|
||||||
|
t.elements[2][1]=0;
|
||||||
|
t.elements[2][2]=1;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void astro_print_matrix(char * title, astro_matrix_t matrix);
|
||||||
|
void astro_print_matrix(char * title, astro_matrix_t matrix) {
|
||||||
|
printf("%s\n", title);
|
||||||
|
for(uint8_t i = 0; i < 3 ; i++) {
|
||||||
|
printf("\t");
|
||||||
|
for(uint8_t j = 0 ; j < 3 ; j++) {
|
||||||
|
printf("%12f", matrix.elements[i][j]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_matrix_t astro_dot_product(astro_matrix_t a, astro_matrix_t b) {
|
||||||
|
astro_matrix_t retval;
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < 3 ; i++) {
|
||||||
|
for(uint8_t j = 0 ; j < 3 ; j++) {
|
||||||
|
double temp = 0;
|
||||||
|
for(uint8_t k = 0; k < 3 ; k++) {
|
||||||
|
temp += a.elements[i][k] * b.elements[k][j];
|
||||||
|
}
|
||||||
|
retval.elements[i][j]=temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_matrix_t astro_transpose_matrix(astro_matrix_t m) {
|
||||||
|
astro_matrix_t retval;
|
||||||
|
for(uint8_t i = 0; i < 3 ; i++) {
|
||||||
|
for(uint8_t j = 0 ; j < 3 ; j++) {
|
||||||
|
retval.elements[i][j] = m.elements[j][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_matrix_t astro_get_precession_matrix(double jd) {
|
||||||
|
//2006 IAU Precession. Implemented from IERS Technical Note No 36 ch5.
|
||||||
|
//https://www.iers.org/SharedDocs/Publikationen/EN/IERS/Publications/tn/TechnNote36/tn36_043.pdf?__blob=publicationFile&v=1
|
||||||
|
|
||||||
|
double t = (jd - 2451545.0) / 36525.0; //5.2
|
||||||
|
const double Arcsec2Radians = M_PI/180.0/60.0/60.0; //Converts arc seconds used in equations below to radians
|
||||||
|
|
||||||
|
double e0 = 84381.406 * Arcsec2Radians; //5.6.4
|
||||||
|
double omegaA = e0 + ((-0.025754 + (0.0512623 + (-0.00772503 + (-0.000000467 + 0.0000003337*t) * t) * t) * t) * t) * Arcsec2Radians; //5.39
|
||||||
|
double psiA = ((5038.481507 + (-1.0790069 + (-0.00114045 + (0.000132851 - 0.0000000951*t) * t) * t) * t) * t) * Arcsec2Radians; //5.39
|
||||||
|
double chiA = ((10.556403 + (-2.3814292 + (-0.00121197 + (0.000170663 - 0.0000000560*t) * t) * t) * t) * t) * Arcsec2Radians; //5.40
|
||||||
|
//Rotation matrix from 5.4.5
|
||||||
|
//(R1(−e0) · R3(psiA) · R1(omegaA) · R3(−chiA))
|
||||||
|
//Above eq rotates from "of date" to J2000, so we reverse the signs to go from J2000 to "of date"
|
||||||
|
astro_matrix_t m1 = astro_get_x_rotation_matrix(e0);
|
||||||
|
astro_matrix_t m2 = astro_get_z_rotation_matrix(-psiA);
|
||||||
|
astro_matrix_t m3 = astro_get_x_rotation_matrix(-omegaA);
|
||||||
|
astro_matrix_t m4 = astro_get_z_rotation_matrix(chiA);
|
||||||
|
|
||||||
|
astro_matrix_t m5 = astro_dot_product(m4, m3);
|
||||||
|
astro_matrix_t m6 = astro_dot_product(m5, m2);
|
||||||
|
astro_matrix_t precessionMatrix = astro_dot_product(m6, m1);
|
||||||
|
|
||||||
|
return precessionMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_cartesian_coordinates_t astro_matrix_multiply(astro_cartesian_coordinates_t v, astro_matrix_t m) {
|
||||||
|
astro_cartesian_coordinates_t t;
|
||||||
|
|
||||||
|
t.x = v.x*m.elements[0][0] + v.y*m.elements[0][1] + v.z*m.elements[0][2];
|
||||||
|
t.y = v.x*m.elements[1][0] + v.y*m.elements[1][1] + v.z*m.elements[1][2];
|
||||||
|
t.z = v.x*m.elements[2][0] + v.y*m.elements[2][1] + v.z*m.elements[2][2];
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Converts cartesian XYZ coordinates to polar (e.g. J2000 xyz to Right Accention and Declication)
|
||||||
|
astro_equatorial_coordinates_t astro_convert_cartesian_to_polar(astro_cartesian_coordinates_t xyz) {
|
||||||
|
astro_equatorial_coordinates_t t;
|
||||||
|
|
||||||
|
t.distance = sqrt(xyz.x * xyz.x + xyz.y * xyz.y + xyz.z * xyz.z);
|
||||||
|
t.declination = acos(xyz.z / t.distance);
|
||||||
|
t.right_ascension = atan2(xyz.y, xyz.x);
|
||||||
|
|
||||||
|
if(t.declination < 0) t.declination += 2 * M_PI;
|
||||||
|
|
||||||
|
if(t.right_ascension < 0) t.right_ascension += 2 * M_PI;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert Geodedic Lat Lon to geocentric XYZ position vector
|
||||||
|
//All angles are input as radians
|
||||||
|
astro_cartesian_coordinates_t astro_convert_geodedic_latlon_to_ITRF_XYZ(double lat, double lon, double height) {
|
||||||
|
//Algorithm from Explanatory Supplement to the Astronomical Almanac 3rd ed. P294
|
||||||
|
const double a = 6378136.6;
|
||||||
|
const double f = 1 / 298.25642;
|
||||||
|
|
||||||
|
const double C = sqrt(((cos(lat)*cos(lat)) + (1.0-f)*(1.0-f) * (sin(lat)*sin(lat))));
|
||||||
|
|
||||||
|
const double S = (1-f)*(1-f)*C;
|
||||||
|
|
||||||
|
double h = height;
|
||||||
|
|
||||||
|
astro_cartesian_coordinates_t r;
|
||||||
|
r.x = (a*C+h) * cos(lat) * cos(lon);
|
||||||
|
r.y = (a*C+h) * cos(lat) * sin(lon);
|
||||||
|
r.z = (a*S+h) * sin(lat);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert position vector to celestial "of date" system.
|
||||||
|
//g(t)=R3(-GAST) r
|
||||||
|
//(Remember to use UT1 for GAST, not ET)
|
||||||
|
//All angles are input and output as radians
|
||||||
|
astro_cartesian_coordinates_t astro_convert_ITRF_to_GCRS(astro_cartesian_coordinates_t r, double ut1) {
|
||||||
|
//This is a simple rotation matrix implemenation about the Z axis, rotation angle is -GMST
|
||||||
|
|
||||||
|
double GMST = astro_get_GMST(ut1);
|
||||||
|
GMST =- GMST * 15.0 * M_PI / 180.0;
|
||||||
|
|
||||||
|
astro_matrix_t m = astro_get_z_rotation_matrix(GMST);
|
||||||
|
astro_cartesian_coordinates_t t = astro_matrix_multiply(r, m);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_cartesian_coordinates_t astro_convert_coordinates_from_meters_to_AU(astro_cartesian_coordinates_t c) {
|
||||||
|
astro_cartesian_coordinates_t t;
|
||||||
|
|
||||||
|
t.x = c.x / 1.49597870691E+11;
|
||||||
|
t.y = c.y / 1.49597870691E+11;
|
||||||
|
t.z = c.z / 1.49597870691E+11;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_cartesian_coordinates_t astro_get_observer_geocentric_coords(double jd, double lat, double lon) {
|
||||||
|
astro_cartesian_coordinates_t r = astro_convert_geodedic_latlon_to_ITRF_XYZ(lat, lon,0);
|
||||||
|
r = astro_convert_ITRF_to_GCRS(r, jd);
|
||||||
|
r = astro_convert_coordinates_from_meters_to_AU(r);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns a body's cartesian coordinates centered on the Sun.
|
||||||
|
//Requires vsop87a_milli_js, if you wish to use a different version of VSOP87, replace the class name vsop87a_milli below
|
||||||
|
astro_cartesian_coordinates_t astro_get_body_coordinates(astro_body_t body, double et) {
|
||||||
|
astro_cartesian_coordinates_t retval = {0};
|
||||||
|
double coords[3];
|
||||||
|
switch(body) {
|
||||||
|
case ASTRO_BODY_SUN:
|
||||||
|
return retval; //Sun is at the center for vsop87a
|
||||||
|
case ASTRO_BODY_MERCURY:
|
||||||
|
vsop87a_milli_getMercury(et, coords);
|
||||||
|
break;
|
||||||
|
case ASTRO_BODY_VENUS:
|
||||||
|
vsop87a_milli_getVenus(et, coords);
|
||||||
|
break;
|
||||||
|
case ASTRO_BODY_EARTH:
|
||||||
|
vsop87a_milli_getEarth(et, coords);
|
||||||
|
break;
|
||||||
|
case ASTRO_BODY_MARS:
|
||||||
|
vsop87a_milli_getMars(et, coords);
|
||||||
|
break;
|
||||||
|
case ASTRO_BODY_JUPITER:
|
||||||
|
vsop87a_milli_getJupiter(et, coords);
|
||||||
|
break;
|
||||||
|
case ASTRO_BODY_SATURN:
|
||||||
|
vsop87a_milli_getSaturn(et, coords);
|
||||||
|
break;
|
||||||
|
case ASTRO_BODY_URANUS:
|
||||||
|
vsop87a_milli_getUranus(et, coords);
|
||||||
|
break;
|
||||||
|
case ASTRO_BODY_NEPTUNE:
|
||||||
|
vsop87a_milli_getNeptune(et, coords);
|
||||||
|
break;
|
||||||
|
case ASTRO_BODY_EMB:
|
||||||
|
vsop87a_milli_getEmb(et, coords);
|
||||||
|
break;
|
||||||
|
case ASTRO_BODY_MOON:
|
||||||
|
{
|
||||||
|
double earth_coords[3];
|
||||||
|
double emb_coords[3];
|
||||||
|
vsop87a_milli_getEarth(et, earth_coords);
|
||||||
|
vsop87a_milli_getEmb(et, emb_coords);
|
||||||
|
vsop87a_milli_getMoon(earth_coords, emb_coords, coords);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.x = coords[0];
|
||||||
|
retval.y = coords[1];
|
||||||
|
retval.z = coords[2];
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_cartesian_coordinates_t astro_get_body_coordinates_light_time_adjusted(astro_body_t body, astro_cartesian_coordinates_t origin, double t) {
|
||||||
|
//Get current position of body
|
||||||
|
astro_cartesian_coordinates_t body_coords = astro_get_body_coordinates(body, t);
|
||||||
|
|
||||||
|
double newT = t;
|
||||||
|
|
||||||
|
for(uint8_t i = 0 ; i < 2 ; i++) {
|
||||||
|
//Calculate light time to body
|
||||||
|
body_coords = astro_subtract_cartesian(body_coords, origin);
|
||||||
|
double distance = sqrt(body_coords.x*body_coords.x + body_coords.y*body_coords.y + body_coords.z*body_coords.z);
|
||||||
|
distance *= 1.496e+11; //Convert from AU to meters
|
||||||
|
double lightTime = distance / 299792458.0;
|
||||||
|
|
||||||
|
//Convert light time to Julian Millenia, and subtract it from the original value of t
|
||||||
|
newT -= lightTime / 24.0 / 60.0 / 60.0 / 365250.0;
|
||||||
|
//Recalculate body position adjusted for light time
|
||||||
|
body_coords = astro_get_body_coordinates(body, newT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return body_coords;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_horizontal_coordinates_t astro_ra_dec_to_alt_az(double jd, double lat, double lon, double ra, double dec) {
|
||||||
|
double GMST = astro_get_GMST(jd) * M_PI/180.0 * 15.0;
|
||||||
|
double h = GMST + lon - ra;
|
||||||
|
|
||||||
|
double sina = sin(dec)*sin(lat) + cos(dec)*cos(h)*cos(lat);
|
||||||
|
double a = asin(sina);
|
||||||
|
|
||||||
|
double cosAz = (sin(dec)*cos(lat) - cos(dec)*cos(h)*sin(lat)) / cos(a);
|
||||||
|
double Az = acos(cosAz);
|
||||||
|
|
||||||
|
if(sin(h) > 0) Az = 2.0*M_PI - Az;
|
||||||
|
|
||||||
|
astro_horizontal_coordinates_t retval;
|
||||||
|
retval.altitude = a;
|
||||||
|
retval.azimuth = Az;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
double astro_degrees_to_radians(double degrees) {
|
||||||
|
return degrees * M_PI / 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
double astro_radians_to_degrees(double radians) {
|
||||||
|
return radians * 180.0 / M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_angle_dms_t astro_radians_to_dms(double radians) {
|
||||||
|
astro_angle_dms_t retval;
|
||||||
|
int8_t sign = (radians < 0) ? -1 : 1;
|
||||||
|
double degrees = fabs(astro_radians_to_degrees(radians));
|
||||||
|
|
||||||
|
retval.degrees = (uint16_t)degrees;
|
||||||
|
double temp = 60.0 * (degrees - retval.degrees);
|
||||||
|
retval.minutes = (uint8_t)temp;
|
||||||
|
retval.seconds = (uint8_t)round(60.0 * (temp - retval.minutes));
|
||||||
|
|
||||||
|
if (retval.seconds > 59) {
|
||||||
|
retval.seconds = 0.0;
|
||||||
|
retval.minutes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval.minutes > 59) {
|
||||||
|
retval.minutes = 0;
|
||||||
|
retval.degrees++;
|
||||||
|
}
|
||||||
|
|
||||||
|
degrees *= sign;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
astro_angle_hms_t astro_radians_to_hms(double radians) {
|
||||||
|
astro_angle_hms_t retval;
|
||||||
|
double degrees = astro_radians_to_degrees(radians);
|
||||||
|
double temp = degrees / 15.0;
|
||||||
|
|
||||||
|
retval.hours = (uint8_t)temp;
|
||||||
|
temp = 60.0 * (temp - retval.hours);
|
||||||
|
retval.minutes = (uint8_t)temp;
|
||||||
|
retval.seconds = (uint8_t)round(60.0 * (temp - retval.minutes));
|
||||||
|
|
||||||
|
if (retval.seconds > 59) {
|
||||||
|
retval.seconds = 0;
|
||||||
|
retval.minutes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval.minutes > 59) {
|
||||||
|
retval.minutes = 0;
|
||||||
|
retval.hours++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
87
movement/lib/astrolib/astrolib.h
Normal file
87
movement/lib/astrolib/astrolib.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Partial C port of Greg Miller's public domain astro library (gmiller@gregmiller.net) 2019
|
||||||
|
* https://github.com/gmiller123456/astrogreg
|
||||||
|
*
|
||||||
|
* Ported by Joey Castillo for Sensor Watch
|
||||||
|
* https://github.com/joeycastillo/Sensor-Watch/
|
||||||
|
*
|
||||||
|
* Public Domain
|
||||||
|
*
|
||||||
|
* THIS 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 ASTROLIB_H_
|
||||||
|
#define ASTROLIB_H_
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ASTRO_BODY_SUN = 0,
|
||||||
|
ASTRO_BODY_MERCURY,
|
||||||
|
ASTRO_BODY_VENUS,
|
||||||
|
ASTRO_BODY_EARTH,
|
||||||
|
ASTRO_BODY_MARS,
|
||||||
|
ASTRO_BODY_JUPITER,
|
||||||
|
ASTRO_BODY_SATURN,
|
||||||
|
ASTRO_BODY_URANUS,
|
||||||
|
ASTRO_BODY_NEPTUNE,
|
||||||
|
ASTRO_BODY_EMB,
|
||||||
|
ASTRO_BODY_MOON
|
||||||
|
} astro_body_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double elements[3][3];
|
||||||
|
} astro_matrix_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
} astro_cartesian_coordinates_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double right_ascension;
|
||||||
|
double declination;
|
||||||
|
double distance;
|
||||||
|
} astro_equatorial_coordinates_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double altitude;
|
||||||
|
double azimuth;
|
||||||
|
} astro_horizontal_coordinates_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int16_t degrees;
|
||||||
|
uint8_t minutes;
|
||||||
|
uint8_t seconds; // you may want this to be a float, watch just can't display any more digits
|
||||||
|
} astro_angle_dms_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t hours;
|
||||||
|
uint8_t minutes;
|
||||||
|
uint8_t seconds; // you may want this to be a float, watch just can't display any more digits
|
||||||
|
} astro_angle_hms_t;
|
||||||
|
|
||||||
|
// Convert a date to a julian date. Must be in UTC+0 time zone!
|
||||||
|
double astro_convert_date_to_julian_date(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second);
|
||||||
|
|
||||||
|
// Converts a Julan Date to Julian Millenia since J2000, which is what VSOP87 expects as input.
|
||||||
|
double astro_convert_jd_to_julian_millenia_since_j2000(double jd);
|
||||||
|
|
||||||
|
// Get right ascension / declination for a given body in the list above.
|
||||||
|
astro_equatorial_coordinates_t astro_get_ra_dec(double jd, astro_body_t bodyNum, double lat, double lon, bool calculate_precession);
|
||||||
|
|
||||||
|
// Convert right ascension / declination to altitude/azimuth for a given location.
|
||||||
|
astro_horizontal_coordinates_t astro_ra_dec_to_alt_az(double jd, double lat, double lon, double ra, double dec);
|
||||||
|
|
||||||
|
// these are self-explanatory
|
||||||
|
double astro_degrees_to_radians(double degrees);
|
||||||
|
double astro_radians_to_degrees(double radians);
|
||||||
|
astro_angle_dms_t astro_radians_to_dms(double radians);
|
||||||
|
astro_angle_hms_t astro_radians_to_hms(double radians);
|
||||||
|
|
||||||
|
#endif // ASTROLIB_H_
|
|
@ -17,6 +17,7 @@ Released to the public domain by Paul Schlyter, December 1992
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "sunriset.h"
|
#include "sunriset.h"
|
||||||
|
|
||||||
|
static void sunpos( double d, double *lon, double *r );
|
||||||
|
|
||||||
/* A macro to compute the number of days elapsed since 2000 Jan 0.0 */
|
/* A macro to compute the number of days elapsed since 2000 Jan 0.0 */
|
||||||
/* (which is equal to 1999 Dec 31, 0h UT) */
|
/* (which is equal to 1999 Dec 31, 0h UT) */
|
||||||
|
@ -199,7 +200,7 @@ double __daylen__( int year, int month, int day, double lon, double lat,
|
||||||
|
|
||||||
/* This function computes the Sun's position at any instant */
|
/* This function computes the Sun's position at any instant */
|
||||||
|
|
||||||
void sunpos( double d, double *lon, double *r )
|
static void sunpos( double d, double *lon, double *r )
|
||||||
/******************************************************/
|
/******************************************************/
|
||||||
/* Computes the Sun's ecliptic longitude and distance */
|
/* Computes the Sun's ecliptic longitude and distance */
|
||||||
/* at an instant given in d, number of days since */
|
/* at an instant given in d, number of days since */
|
||||||
|
|
|
@ -24,8 +24,6 @@ double __daylen__( int year, int month, int day, double lon, double lat,
|
||||||
int __sunriset__( int year, int month, int day, double lon, double lat,
|
int __sunriset__( int year, int month, int day, double lon, double lat,
|
||||||
double altit, int upper_limb, double *rise, double *set );
|
double altit, int upper_limb, double *rise, double *set );
|
||||||
|
|
||||||
void sunpos( double d, double *lon, double *r );
|
|
||||||
|
|
||||||
void sun_RA_dec( double d, double *RA, double *dec, double *r );
|
void sun_RA_dec( double d, double *RA, double *dec, double *r );
|
||||||
|
|
||||||
double revolution( double x );
|
double revolution( double x );
|
||||||
|
|
5
movement/lib/vsop87/LICENSE.txt
Executable file
5
movement/lib/vsop87/LICENSE.txt
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
Author: Greg A Miller (gmiller@gregmiller.net)
|
||||||
|
I release all of my work in this project to the public domain.
|
||||||
|
|
||||||
|
Note, though, not everything here can be considered my work. The VSOP87 theory is the work of
|
||||||
|
Bureau des Longitudes.
|
143
movement/lib/vsop87/README.md
Executable file
143
movement/lib/vsop87/README.md
Executable file
|
@ -0,0 +1,143 @@
|
||||||
|
# Example
|
||||||
|
|
||||||
|
An example in JavaScript showing computations is available at http://www.celestialprogramming.com/vsop87-multilang/
|
||||||
|
|
||||||
|
### Current Stauts
|
||||||
|
Versions for many different languages and environments have been created. These have passed all test cases provided by the
|
||||||
|
VSOP87 authors, a validation program is also included for each language. They are ready for use. See the "Languages" directory for the status
|
||||||
|
of each language.
|
||||||
|
|
||||||
|
Still to come: more languages, documentation, and examples.
|
||||||
|
|
||||||
|
# About this Project
|
||||||
|
The purpose of this project is to create versions of VSOP87 in many different languages. The plan is to generate a initial version in C# truncated to different
|
||||||
|
precisions, then convert the resulting files into other languages. This project was inspired by the [Neoprogrammics Source Code Generator Tool](http://www.neoprogrammics.com/vsop87/source_code_generator_tool/).
|
||||||
|
The goal of this project is to provide easier to use (readymade source files), include all data (e.g. the Moon and velocities), are truncated to different accuracy levels,
|
||||||
|
, for more languages, and have a more permissive license (public domain). It will provide tests against the original VSOP87 test data for each programming language to validate correctness, as well as examples to show common useage.
|
||||||
|
|
||||||
|
# Language Status
|
||||||
|
|
||||||
|
Below is a list of the planned languages and their current status.
|
||||||
|
|
||||||
|
|
||||||
|
Language |Inline|JSON|CSV|CSV Low Mem|Validation Tests|Alt Az Reduction Example
|
||||||
|
-------------|------|----|---|-----------|----------------|--------------
|
||||||
|
Java |Yes | |Yes| |Pass |
|
||||||
|
C |Yes | | |Yes |Pass |
|
||||||
|
C# |Yes | |Yes| |Pass |
|
||||||
|
Python |Yes |Yes |Yes| |Pass |
|
||||||
|
C++ |Yes | | | |Pass |
|
||||||
|
VB.Net |Yes | | | |Pass |
|
||||||
|
JavaScript |Yes |Yes | | |Pass |Yes
|
||||||
|
PHP |Yes | | | |Pass |
|
||||||
|
Ruby |Yes | | | |Pass |
|
||||||
|
Swift |Yes | | | |Pass |
|
||||||
|
Matlab/Octave|Yes | | | |Pass |
|
||||||
|
Groovy | | |Yes| |Pass |
|
||||||
|
Go |Yes | | | |Pass |
|
||||||
|
Pascal |Yes | | | |0.000009au |
|
||||||
|
Perl |Yes | | |Yes |Pass |
|
||||||
|
R |Fail! | | | |Fail! |
|
||||||
|
Cobol | | | | | |
|
||||||
|
Fortran | | | | | |
|
||||||
|
Rust |Yes | | | |Pass |
|
||||||
|
Arduino |Yes | | | |0.000009au |
|
||||||
|
|
||||||
|
# What is VSOP87? Why use it?
|
||||||
|
VSOP87 is one of many solutions available for predicting the positions of the planets (plus the Sun and the Moon) in our solar system. The actual name is
|
||||||
|
Variations S<>culaires des Orbites Plan<61>taires, and it was published in 1987 by the Bureau des Longitudes. Even though there have been many other methods
|
||||||
|
developed before and after VSOP87, it remains one of the most popular methods among amatuers. It provides better accuracy than most amatuers require (.1 arcseconds)
|
||||||
|
over a period of a few thousand years before and after the year 2000.
|
||||||
|
|
||||||
|
# Implementation Types
|
||||||
|
There are a few different types of implementations: Inline, JSON, CSV, and CSV Low Memory. The inline versions are generally the easiest to use as they will have no
|
||||||
|
external requirements, they are also the easiest to generate, so they're available for more languages. The JSON versions require a JSON file (located in the
|
||||||
|
languages/JSON folder) which is loaded into memory. The advantages of the JSON versions are you can compute the velocities with the same data the positions
|
||||||
|
are generated from, and you can load and dispose of the memory used by the data when you need it. The CSV implementations are similar to the JSON implementations,
|
||||||
|
but, obviously, read from a CSV file (located in the languages/CSV folder). And the Low Memory CSV implementations read the same CSV files, but the
|
||||||
|
data is not retained in memory. The JSON versions are located in the Languages/JSON directory, as well as the required JSON files, and the CSV implementations
|
||||||
|
are in the languages/CSV folder.
|
||||||
|
|
||||||
|
# Which Version Should I Use?
|
||||||
|
For the overwhelming majority of users, the VSOP87A_full version will be all that you need. This is the full version, but should still be fast enough and small enough
|
||||||
|
for most use cases. Using the full version eliminates any questions of whether it will be accurate enough. If, after trying the full version, the computation isn't
|
||||||
|
fast enough, from there you should experiment with truncated versions. The VSOP87A versions are the only versions which include both the Earth and Moon. VSOP87A doesn't include the moon directly, but does include the Earth and the Earth-Moon Barrycenter, and all provided code for the VSOP87A versions include a function to compute the Moon's position from the Earth and EMB. Using the versions that provide the velocities is necessary if you want to account for relativistic effects do to the motion of the observer.
|
||||||
|
|
||||||
|
There are several versions of the main theory. The first is just called VSOP87, the remainder of them are appended with the letters A, B, C, D, E. Each version
|
||||||
|
provides the data in a slightly different form.
|
||||||
|
|
||||||
|
Version|Mercury|Venus|Earth|EMB|Mars|Jupiter|Saturn|Uranus|Neptune|Sun|Coordinates
|
||||||
|
-------|-------|-----|-----|---|----|-------|------|------|-------|---|-----------
|
||||||
|
VSOP87|Yes|Yes|No|Yes|Yes|Yes|Yes|Yes|Yes|No|Keperian Orbital Elements
|
||||||
|
VSOP87A|Yes|Yes|Yes|Yes|Yes|Yes|Yes|Yes|Yes|No|Heliocentric J2000 Ecliptic Rectangular XYZ
|
||||||
|
VSOP87B|Yes|Yes|Yes|No|Yes|Yes|Yes|Yes|Yes|No|Heliocentric J2000 Ecliptic Spherical LBR
|
||||||
|
VSOP87C|Yes|Yes|Yes|No|Yes|Yes|Yes|Yes|Yes|No|Heliocentric Ecliptic of date Rectangular XYZ
|
||||||
|
VSOP87D|Yes|Yes|Yes|No|Yes|Yes|Yes|Yes|Yes|No|Heliocentric Ecliptic of date Spherical LBR
|
||||||
|
VSOP87E|Yes|Yes|Yes|No|Yes|Yes|Yes|Yes|Yes|Yes|Barycentric J2000 Ecliptic Rectangular XYZ
|
||||||
|
|
||||||
|
# Truncated versions
|
||||||
|
Since the full VSOP87 provides more accuracy than most amateurs require, the algorithm can be shortened by eliminating terms. This speeds up the computations, and
|
||||||
|
reduces the overall size of the code at the cost of accuracy. For each programming language, this project supplies VSOP87 truncated at ten different levels. The
|
||||||
|
effects of accuracy are detailed in the graphs below. Each level of truncation eliminates any terms with a coefficient 1/10 the previous truncation level.
|
||||||
|
|
||||||
|
Trunaction Level|Total Terms|Skipped Terms|Percent Skipped
|
||||||
|
----------------|-----------|-------------|---------------
|
||||||
|
full |269949|0 |0 %
|
||||||
|
xx large |269949|20998 |7.7 %
|
||||||
|
x large |269949|67848 |25.1 %
|
||||||
|
large |269949|145031|53.7 %
|
||||||
|
small |269949|218559|80.9 %
|
||||||
|
x small |269949|250204|92.6 %
|
||||||
|
milli |269949|262369|97.1 %
|
||||||
|
micro |269949|266975|98.8 %
|
||||||
|
nano |269949|268686|99.5 %
|
||||||
|
pico |269949|269464|99.8 %
|
||||||
|
|
||||||
|
# Accuracy
|
||||||
|
|
||||||
|
Accuracy graphs are below. They show the error in degrees of each body as viewed from Earth. Each graph shows the error for one body for all truncated versions of
|
||||||
|
VSOP87. The error is vs. the full version of VSOP87, so the inherent error in VSOP87 also has to be added. Some bodies appear twice, to zoom in on the lower portion
|
||||||
|
of the graph, as the error of the pico version makes it difficult to see errors amongst the larger versions. The Python script and data to reproduce the graphs is
|
||||||
|
in the Accuracy folder, by regenerating them you can use the Matplotlib interface to explore the graphs further.
|
||||||
|
|
||||||
|
Since the error is computed from the geocenter, the Earth does not appear in the graphs below, nor does the Sun. Graphs are also not present for the Moon, but graphs
|
||||||
|
are available for the Earth-Moon Barrycenter (EMB), the error for the Moon will be a linear function of the EMB error.
|
||||||
|
|
||||||
|
The full VSOP87 accuracy is .1 arcseconds for Saturn, and better for all others. For more details on accuracy of the full theory consult
|
||||||
|
[Planetary theories in rectangular and spherical variables - VSOP 87 solutions](http://articles.adsabs.harvard.edu/full/1988A%26A...202..309B).
|
||||||
|
|
||||||
|
### Mercury
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/mercury.png)
|
||||||
|
|
||||||
|
### Venus
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/venus.png)
|
||||||
|
|
||||||
|
### Earth-Moon Barrycenter
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/emb.png)
|
||||||
|
|
||||||
|
### Earth-Moon Barrycenter (zoomed)
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/emb2.png)
|
||||||
|
|
||||||
|
### Mars
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/mars.png)
|
||||||
|
|
||||||
|
### Jupiter
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/jupiter.png)
|
||||||
|
|
||||||
|
### Saturn
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/saturn.png)
|
||||||
|
|
||||||
|
### Saturn (zoomed)
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/saturn2.png)
|
||||||
|
|
||||||
|
### Uranus
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/uranus.png)
|
||||||
|
|
||||||
|
### Uranus (zoomed)
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/uranus2.png)
|
||||||
|
|
||||||
|
### Neptune
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/neptune.png)
|
||||||
|
|
||||||
|
### Neptune (zoomed)
|
||||||
|
![Mercury](https://raw.githubusercontent.com/gmiller123456/vsop87-multilang/master/utility/Accuracy/neptune2.png)
|
1019
movement/lib/vsop87/vsop87a_micro.c
Executable file
1019
movement/lib/vsop87/vsop87a_micro.c
Executable file
File diff suppressed because it is too large
Load diff
17
movement/lib/vsop87/vsop87a_micro.h
Executable file
17
movement/lib/vsop87/vsop87a_micro.h
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
//VSOP87-Multilang http://www.astrogreg.com/vsop87-multilang/index.html
|
||||||
|
//Greg Miller (gmiller@gregmiller.net) 2019. Released as Public Domain
|
||||||
|
|
||||||
|
#ifndef VSOP87A_MICRO
|
||||||
|
#define VSOP87A_MICRO
|
||||||
|
|
||||||
|
void vsop87a_micro_getEarth(double t,double temp[]);
|
||||||
|
void vsop87a_micro_getEmb(double t,double temp[]);
|
||||||
|
void vsop87a_micro_getJupiter(double t,double temp[]);
|
||||||
|
void vsop87a_micro_getMars(double t,double temp[]);
|
||||||
|
void vsop87a_micro_getMercury(double t,double temp[]);
|
||||||
|
void vsop87a_micro_getNeptune(double t,double temp[]);
|
||||||
|
void vsop87a_micro_getSaturn(double t,double temp[]);
|
||||||
|
void vsop87a_micro_getUranus(double t,double temp[]);
|
||||||
|
void vsop87a_micro_getVenus(double t,double temp[]);
|
||||||
|
void vsop87a_micro_getMoon(double earth[], double emb[],double temp[]);
|
||||||
|
#endif
|
2048
movement/lib/vsop87/vsop87a_milli.c
Executable file
2048
movement/lib/vsop87/vsop87a_milli.c
Executable file
File diff suppressed because it is too large
Load diff
17
movement/lib/vsop87/vsop87a_milli.h
Executable file
17
movement/lib/vsop87/vsop87a_milli.h
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
//VSOP87-Multilang http://www.astrogreg.com/vsop87-multilang/index.html
|
||||||
|
//Greg Miller (gmiller@gregmiller.net) 2019. Released as Public Domain
|
||||||
|
|
||||||
|
#ifndef VSOP87A_MILLI
|
||||||
|
#define VSOP87A_MILLI
|
||||||
|
|
||||||
|
void vsop87a_milli_getEarth(double t,double temp[]);
|
||||||
|
void vsop87a_milli_getEmb(double t,double temp[]);
|
||||||
|
void vsop87a_milli_getJupiter(double t,double temp[]);
|
||||||
|
void vsop87a_milli_getMars(double t,double temp[]);
|
||||||
|
void vsop87a_milli_getMercury(double t,double temp[]);
|
||||||
|
void vsop87a_milli_getNeptune(double t,double temp[]);
|
||||||
|
void vsop87a_milli_getSaturn(double t,double temp[]);
|
||||||
|
void vsop87a_milli_getUranus(double t,double temp[]);
|
||||||
|
void vsop87a_milli_getVenus(double t,double temp[]);
|
||||||
|
void vsop87a_milli_getMoon(double earth[], double emb[],double temp[]);
|
||||||
|
#endif
|
1
movement/make/.gitignore
vendored
1
movement/make/.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
build/
|
build/
|
||||||
|
firmware/
|
||||||
|
|
|
@ -18,6 +18,8 @@ INCLUDES += \
|
||||||
-I../watch_faces/demo/ \
|
-I../watch_faces/demo/ \
|
||||||
-I../lib/TOTP-MCU/ \
|
-I../lib/TOTP-MCU/ \
|
||||||
-I../lib/sunriset/ \
|
-I../lib/sunriset/ \
|
||||||
|
-I../lib/vsop87/ \
|
||||||
|
-I../lib/astrolib/ \
|
||||||
|
|
||||||
# If you add any other source files you wish to compile, add them after ../app.c
|
# If you add any other source files you wish to compile, add them after ../app.c
|
||||||
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
|
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
|
||||||
|
@ -29,6 +31,8 @@ SRCS += \
|
||||||
../lib/TOTP-MCU/sha1.c \
|
../lib/TOTP-MCU/sha1.c \
|
||||||
../lib/TOTP-MCU/TOTP.c \
|
../lib/TOTP-MCU/TOTP.c \
|
||||||
../lib/sunriset/sunriset.c \
|
../lib/sunriset/sunriset.c \
|
||||||
|
../lib/vsop87/vsop87a_milli.c \
|
||||||
|
../lib/astrolib/astrolib.c \
|
||||||
../movement.c \
|
../movement.c \
|
||||||
../watch_faces/clock/simple_clock_face.c \
|
../watch_faces/clock/simple_clock_face.c \
|
||||||
../watch_faces/clock/world_clock_face.c \
|
../watch_faces/clock/world_clock_face.c \
|
||||||
|
@ -37,9 +41,10 @@ SRCS += \
|
||||||
../watch_faces/settings/set_time_face.c \
|
../watch_faces/settings/set_time_face.c \
|
||||||
../watch_faces/sensor/thermistor_readout_face.c \
|
../watch_faces/sensor/thermistor_readout_face.c \
|
||||||
../watch_faces/sensor/thermistor_logging_face.c \
|
../watch_faces/sensor/thermistor_logging_face.c \
|
||||||
|
../watch_faces/sensor/thermistor_testing_face.c \
|
||||||
../watch_faces/demo/character_set_face.c \
|
../watch_faces/demo/character_set_face.c \
|
||||||
../watch_faces/demo/voltage_face.c \
|
../watch_faces/demo/voltage_face.c \
|
||||||
../watch_faces/demo/lis2dh_logging_face.c \
|
../watch_faces/demo/lis2dw_logging_face.c \
|
||||||
../watch_faces/demo/demo_face.c \
|
../watch_faces/demo/demo_face.c \
|
||||||
../watch_faces/demo/hello_there_face.c \
|
../watch_faces/demo/hello_there_face.c \
|
||||||
../watch_faces/complication/pulsometer_face.c \
|
../watch_faces/complication/pulsometer_face.c \
|
||||||
|
@ -48,9 +53,14 @@ SRCS += \
|
||||||
../watch_faces/complication/totp_face.c \
|
../watch_faces/complication/totp_face.c \
|
||||||
../watch_faces/complication/sunrise_sunset_face.c \
|
../watch_faces/complication/sunrise_sunset_face.c \
|
||||||
../watch_faces/complication/countdown_face.c \
|
../watch_faces/complication/countdown_face.c \
|
||||||
|
../watch_faces/complication/counter_face.c \
|
||||||
../watch_faces/complication/blinky_face.c \
|
../watch_faces/complication/blinky_face.c \
|
||||||
../watch_faces/complication/moon_phase_face.c \
|
../watch_faces/complication/moon_phase_face.c \
|
||||||
../watch_faces/sensor/accelerometer_data_acquisition_face.c \
|
../watch_faces/sensor/accelerometer_data_acquisition_face.c \
|
||||||
|
../watch_faces/clock/mars_time_face.c \
|
||||||
|
../watch_faces/complication/orrery_face.c \
|
||||||
|
../watch_faces/complication/astronomy_face.c \
|
||||||
|
../watch_faces/complication/tomato_face.c \
|
||||||
# New watch faces go above this line.
|
# New watch faces go above this line.
|
||||||
|
|
||||||
# Leave this line at the bottom of the file; it has all the targets for making your project.
|
# Leave this line at the bottom of the file; it has all the targets for making your project.
|
||||||
|
|
36
movement/make/make_alternate_fw.sh
Executable file
36
movement/make/make_alternate_fw.sh
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
fw_dir="firmware/download"
|
||||||
|
sim_dir="firmware/simulate"
|
||||||
|
colors=("green" "blue")
|
||||||
|
variants=("standard" "alt_time" "deep_space_now" "focus" "the_athlete" "the_backpacker" "the_stargazer")
|
||||||
|
|
||||||
|
if [ -d "$fw_dir" ] ; then
|
||||||
|
rm -r "$fw_dir"
|
||||||
|
fi
|
||||||
|
if [ -d "$sim_dir" ] ; then
|
||||||
|
rm -r "$sim_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$fw_dir"
|
||||||
|
mkdir -p "$sim_dir"
|
||||||
|
|
||||||
|
for variant in "${variants[@]}"
|
||||||
|
do
|
||||||
|
VARIANT=$(echo "$variant" | tr '[:lower:]' '[:upper:]')
|
||||||
|
for color in "${colors[@]}"
|
||||||
|
do
|
||||||
|
COLOR=$(echo "$color" | tr '[:lower:]' '[:upper:]')
|
||||||
|
make clean
|
||||||
|
make LED=$COLOR FIRMWARE=$VARIANT
|
||||||
|
mv "build/watch.uf2" "$fw_dir/$variant-$color.uf2"
|
||||||
|
done
|
||||||
|
make clean
|
||||||
|
emmake make FIRMWARE=$VARIANT
|
||||||
|
mkdir "$sim_dir/$variant/"
|
||||||
|
mv "build/watch.wasm" "$sim_dir/$variant/"
|
||||||
|
mv "build/watch.js" "$sim_dir/$variant/"
|
||||||
|
mv "build/watch.html" "$sim_dir/$variant/index.html"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Done."
|
|
@ -27,7 +27,24 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "watch.h"
|
#include "watch.h"
|
||||||
#include "movement.h"
|
#include "movement.h"
|
||||||
|
|
||||||
|
#ifndef MOVEMENT_FIRMWARE
|
||||||
#include "movement_config.h"
|
#include "movement_config.h"
|
||||||
|
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_STANDARD
|
||||||
|
#include "alt_fw/standard.h"
|
||||||
|
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_ALT_TIME
|
||||||
|
#include "alt_fw/alt_time.h"
|
||||||
|
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_FOCUS
|
||||||
|
#include "alt_fw/focus.h"
|
||||||
|
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_THE_BACKPACKER
|
||||||
|
#include "alt_fw/the_backpacker.h"
|
||||||
|
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_THE_ATHLETE
|
||||||
|
#include "alt_fw/the_athlete.h"
|
||||||
|
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_THE_STARGAZER
|
||||||
|
#include "alt_fw/the_stargazer.h"
|
||||||
|
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_DEEP_SPACE_NOW
|
||||||
|
#include "alt_fw/deep_space_now.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if __EMSCRIPTEN__
|
#if __EMSCRIPTEN__
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
|
@ -256,6 +273,10 @@ void app_setup(void) {
|
||||||
static bool is_first_launch = true;
|
static bool is_first_launch = true;
|
||||||
|
|
||||||
if (is_first_launch) {
|
if (is_first_launch) {
|
||||||
|
#ifdef MOVEMENT_CUSTOM_BOOT_COMMANDS
|
||||||
|
MOVEMENT_CUSTOM_BOOT_COMMANDS()
|
||||||
|
#endif
|
||||||
|
|
||||||
for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) {
|
for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) {
|
||||||
watch_face_contexts[i] = NULL;
|
watch_face_contexts[i] = NULL;
|
||||||
scheduled_tasks[i].reg = 0;
|
scheduled_tasks[i].reg = 0;
|
||||||
|
|
|
@ -28,8 +28,11 @@
|
||||||
#include "movement_faces.h"
|
#include "movement_faces.h"
|
||||||
|
|
||||||
const watch_face_t watch_faces[] = {
|
const watch_face_t watch_faces[] = {
|
||||||
accelerometer_data_acquisition_face,
|
|
||||||
simple_clock_face,
|
simple_clock_face,
|
||||||
|
world_clock_face,
|
||||||
|
sunrise_sunset_face,
|
||||||
|
moon_phase_face,
|
||||||
|
thermistor_readout_face,
|
||||||
preferences_face,
|
preferences_face,
|
||||||
set_time_face,
|
set_time_face,
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,20 +32,26 @@
|
||||||
#include "pulsometer_face.h"
|
#include "pulsometer_face.h"
|
||||||
#include "thermistor_readout_face.h"
|
#include "thermistor_readout_face.h"
|
||||||
#include "thermistor_logging_face.h"
|
#include "thermistor_logging_face.h"
|
||||||
|
#include "thermistor_testing_face.h"
|
||||||
#include "character_set_face.h"
|
#include "character_set_face.h"
|
||||||
#include "beats_face.h"
|
#include "beats_face.h"
|
||||||
#include "day_one_face.h"
|
#include "day_one_face.h"
|
||||||
#include "voltage_face.h"
|
#include "voltage_face.h"
|
||||||
#include "stopwatch_face.h"
|
#include "stopwatch_face.h"
|
||||||
#include "totp_face.h"
|
#include "totp_face.h"
|
||||||
#include "lis2dh_logging_face.h"
|
#include "lis2dw_logging_face.h"
|
||||||
#include "demo_face.h"
|
#include "demo_face.h"
|
||||||
#include "hello_there_face.h"
|
#include "hello_there_face.h"
|
||||||
#include "sunrise_sunset_face.h"
|
#include "sunrise_sunset_face.h"
|
||||||
#include "countdown_face.h"
|
#include "countdown_face.h"
|
||||||
|
#include "counter_face.h"
|
||||||
#include "blinky_face.h"
|
#include "blinky_face.h"
|
||||||
#include "moon_phase_face.h"
|
#include "moon_phase_face.h"
|
||||||
#include "accelerometer_data_acquisition_face.h"
|
#include "accelerometer_data_acquisition_face.h"
|
||||||
|
#include "mars_time_face.h"
|
||||||
|
#include "orrery_face.h"
|
||||||
|
#include "astronomy_face.h"
|
||||||
|
#include "tomato_face.h"
|
||||||
// New includes go above this line.
|
// New includes go above this line.
|
||||||
|
|
||||||
#endif // MOVEMENT_FACES_H_
|
#endif // MOVEMENT_FACES_H_
|
||||||
|
|
|
@ -52,6 +52,7 @@ bool <#watch_face_name#>_face_loop(movement_event_t event, movement_settings_t *
|
||||||
break;
|
break;
|
||||||
case EVENT_TICK:
|
case EVENT_TICK:
|
||||||
// If needed, update your display here.
|
// If needed, update your display here.
|
||||||
|
break;
|
||||||
case EVENT_MODE_BUTTON_UP:
|
case EVENT_MODE_BUTTON_UP:
|
||||||
// You shouldn't need to change this case; Mode almost always moves to the next watch face.
|
// You shouldn't need to change this case; Mode almost always moves to the next watch face.
|
||||||
movement_move_to_next_face();
|
movement_move_to_next_face();
|
||||||
|
|
165
movement/watch_faces/clock/mars_time_face.c
Normal file
165
movement/watch_faces/clock/mars_time_face.c
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "watch_utility.h"
|
||||||
|
#include "mars_time_face.h"
|
||||||
|
|
||||||
|
// note: lander coordinates come from Mars24's `marslandmarks.xml` file
|
||||||
|
static double site_longitudes[MARS_TIME_NUM_SITES] = {
|
||||||
|
0, // Mars Coordinated Time, at the meridian
|
||||||
|
360.0 - 109.9, // Zhurong lander site
|
||||||
|
360.0 - 77.45088572, // Perseverance lander site
|
||||||
|
360.0 - 135.623447, // InSight lander site
|
||||||
|
360.0 - 137.441635, // Curiosity lander site
|
||||||
|
};
|
||||||
|
|
||||||
|
static char site_names[MARS_TIME_NUM_SITES][3] = {
|
||||||
|
"MC",
|
||||||
|
"ZH",
|
||||||
|
"PE",
|
||||||
|
"IN",
|
||||||
|
"CU",
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint16_t landing_sols[MARS_TIME_NUM_SITES] = {
|
||||||
|
0,
|
||||||
|
52387,
|
||||||
|
52304,
|
||||||
|
51511,
|
||||||
|
49269,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t minute;
|
||||||
|
uint8_t second;
|
||||||
|
} mars_clock_hms_t;
|
||||||
|
|
||||||
|
static void _h_to_hms(mars_clock_hms_t *date_time, double h) {
|
||||||
|
unsigned int seconds = (unsigned int)(h * 3600.0);
|
||||||
|
date_time->hour = seconds / 3600;
|
||||||
|
seconds = seconds % 3600;
|
||||||
|
date_time->minute = floor(seconds / 60);
|
||||||
|
date_time->second = round(seconds % 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _update(movement_settings_t *settings, mars_time_state_t *state) {
|
||||||
|
char buf[11];
|
||||||
|
watch_date_time date_time = watch_rtc_get_date_time();
|
||||||
|
uint32_t now = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
|
||||||
|
// TODO: I'm skipping over some steps here.
|
||||||
|
// https://www.giss.nasa.gov/tools/mars24/help/algorithm.html
|
||||||
|
double jdut = 2440587.5 + ((double)now / 86400.0);
|
||||||
|
double jdtt = jdut + ((37.0 + 32.184) / 86400.0);
|
||||||
|
double jd2k = jdtt - 2451545.0;
|
||||||
|
double msd = ((jd2k - 4.5) / 1.0274912517) + 44796.0 - 0.0009626;
|
||||||
|
double mtc = fmod(24 * msd, 24);
|
||||||
|
double lmt;
|
||||||
|
|
||||||
|
if (state->current_site == 0) {
|
||||||
|
lmt = mtc;
|
||||||
|
} else {
|
||||||
|
double longitude = site_longitudes[state->current_site];
|
||||||
|
double lmst = mtc - ((longitude * 24.0) / 360.0);
|
||||||
|
lmt = fmod(lmst + 24, 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->displaying_sol) {
|
||||||
|
// TODO: this is not right, mission sol should turn over at midnight local time?
|
||||||
|
uint16_t sol = floor(msd) - landing_sols[state->current_site];
|
||||||
|
if (sol < 1000) sprintf(&buf[0], "%s Sol%3d", site_names[state->current_site], sol);
|
||||||
|
else sprintf(&buf[0], "%s $%6d", site_names[state->current_site], sol);
|
||||||
|
watch_clear_colon();
|
||||||
|
watch_clear_indicator(WATCH_INDICATOR_24H);
|
||||||
|
} else {
|
||||||
|
mars_clock_hms_t mars_time;
|
||||||
|
_h_to_hms(&mars_time, lmt);
|
||||||
|
sprintf(&buf[0], "%s %02d%02d%02d", site_names[state->current_site], mars_time.hour, mars_time.minute, mars_time.second);
|
||||||
|
watch_set_colon();
|
||||||
|
watch_set_indicator(WATCH_INDICATOR_24H);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mars_time_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||||
|
(void) settings;
|
||||||
|
(void) watch_face_index;
|
||||||
|
if (*context_ptr == NULL) {
|
||||||
|
*context_ptr = malloc(sizeof(mars_time_state_t));
|
||||||
|
memset(*context_ptr, 0, sizeof(mars_time_state_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mars_time_face_activate(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
mars_time_state_t *state = (mars_time_state_t *)context;
|
||||||
|
(void) state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mars_time_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||||
|
mars_time_state_t *state = (mars_time_state_t *)context;
|
||||||
|
|
||||||
|
switch (event.event_type) {
|
||||||
|
case EVENT_ACTIVATE:
|
||||||
|
case EVENT_TICK:
|
||||||
|
_update(settings, state);
|
||||||
|
break;
|
||||||
|
case EVENT_MODE_BUTTON_UP:
|
||||||
|
movement_move_to_next_face();
|
||||||
|
break;
|
||||||
|
case EVENT_LIGHT_BUTTON_UP:
|
||||||
|
state->displaying_sol = !state->displaying_sol;
|
||||||
|
_update(settings, state);
|
||||||
|
break;
|
||||||
|
case EVENT_LIGHT_LONG_PRESS:
|
||||||
|
movement_illuminate_led();
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_BUTTON_UP:
|
||||||
|
state->current_site = (state->current_site + 1) % MARS_TIME_NUM_SITES;
|
||||||
|
_update(settings, state);
|
||||||
|
break;
|
||||||
|
case EVENT_TIMEOUT:
|
||||||
|
// TODO: make this lower power so we can avoid timeout
|
||||||
|
movement_move_to_face(0);
|
||||||
|
break;
|
||||||
|
case EVENT_LOW_ENERGY_UPDATE:
|
||||||
|
// TODO: low energy update
|
||||||
|
// watch_start_tick_animation(500);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mars_time_face_resign(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
(void) context;
|
||||||
|
}
|
||||||
|
|
58
movement/watch_faces/clock/mars_time_face.h
Normal file
58
movement/watch_faces/clock/mars_time_face.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 MARS_TIME_FACE_H_
|
||||||
|
#define MARS_TIME_FACE_H_
|
||||||
|
|
||||||
|
#include "movement.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MARS_TIME_MERIDIAN,
|
||||||
|
MARS_TIME_ZHURONG_SITE,
|
||||||
|
MARS_TIME_PERSEVERANCE_SITE,
|
||||||
|
MARS_TIME_INSIGHT_SITE,
|
||||||
|
MARS_TIME_CURIOSITY_SITE,
|
||||||
|
MARS_TIME_NUM_SITES,
|
||||||
|
} mars_time_site_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
mars_time_site_t current_site;
|
||||||
|
bool displaying_sol;
|
||||||
|
} mars_time_state_t;
|
||||||
|
|
||||||
|
void mars_time_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||||
|
void mars_time_face_activate(movement_settings_t *settings, void *context);
|
||||||
|
bool mars_time_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||||
|
void mars_time_face_resign(movement_settings_t *settings, void *context);
|
||||||
|
|
||||||
|
#define mars_time_face ((const watch_face_t){ \
|
||||||
|
mars_time_face_setup, \
|
||||||
|
mars_time_face_activate, \
|
||||||
|
mars_time_face_loop, \
|
||||||
|
mars_time_face_resign, \
|
||||||
|
NULL, \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif // MARS_TIME_FACE_H_
|
||||||
|
|
|
@ -82,11 +82,11 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting
|
||||||
// ...and set the LAP indicator if low.
|
// ...and set the LAP indicator if low.
|
||||||
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
||||||
|
|
||||||
if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
// everything before seconds is the same, don't waste cycles setting those segments.
|
// everything before seconds is the same, don't waste cycles setting those segments.
|
||||||
pos = 8;
|
pos = 8;
|
||||||
sprintf(buf, "%02d", date_time.unit.second);
|
sprintf(buf, "%02d", date_time.unit.second);
|
||||||
} else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
} else if ((date_time.reg >> 12) == (previous_date_time >> 12) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
// everything before minutes is the same.
|
// everything before minutes is the same.
|
||||||
pos = 6;
|
pos = 6;
|
||||||
sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second);
|
sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second);
|
||||||
|
|
|
@ -44,14 +44,11 @@ void world_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_in
|
||||||
}
|
}
|
||||||
|
|
||||||
void world_clock_face_activate(movement_settings_t *settings, void *context) {
|
void world_clock_face_activate(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
world_clock_state_t *state = (world_clock_state_t *)context;
|
world_clock_state_t *state = (world_clock_state_t *)context;
|
||||||
state->current_screen = 0;
|
state->current_screen = 0;
|
||||||
state->previous_date_time = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
||||||
if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
|
|
||||||
|
|
||||||
watch_set_colon();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool world_clock_face_do_display_mode(movement_event_t event, movement_settings_t *settings, world_clock_state_t *state) {
|
static bool world_clock_face_do_display_mode(movement_event_t event, movement_settings_t *settings, world_clock_state_t *state) {
|
||||||
|
@ -63,6 +60,10 @@ static bool world_clock_face_do_display_mode(movement_event_t event, movement_se
|
||||||
watch_date_time date_time;
|
watch_date_time date_time;
|
||||||
switch (event.event_type) {
|
switch (event.event_type) {
|
||||||
case EVENT_ACTIVATE:
|
case EVENT_ACTIVATE:
|
||||||
|
if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
|
||||||
|
watch_set_colon();
|
||||||
|
state->previous_date_time = 0xFFFFFFFF;
|
||||||
|
// fall through
|
||||||
case EVENT_TICK:
|
case EVENT_TICK:
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
case EVENT_LOW_ENERGY_UPDATE:
|
||||||
date_time = watch_rtc_get_date_time();
|
date_time = watch_rtc_get_date_time();
|
||||||
|
@ -71,11 +72,11 @@ static bool world_clock_face_do_display_mode(movement_event_t event, movement_se
|
||||||
previous_date_time = state->previous_date_time;
|
previous_date_time = state->previous_date_time;
|
||||||
state->previous_date_time = date_time.reg;
|
state->previous_date_time = date_time.reg;
|
||||||
|
|
||||||
if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
// everything before seconds is the same, don't waste cycles setting those segments.
|
// everything before seconds is the same, don't waste cycles setting those segments.
|
||||||
pos = 8;
|
pos = 8;
|
||||||
sprintf(buf, "%02d", date_time.unit.second);
|
sprintf(buf, "%02d", date_time.unit.second);
|
||||||
} else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
} else if ((date_time.reg >> 12) == (previous_date_time >> 12) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
// everything before minutes is the same.
|
// everything before minutes is the same.
|
||||||
pos = 6;
|
pos = 6;
|
||||||
sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second);
|
sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second);
|
||||||
|
@ -140,9 +141,9 @@ static bool _world_clock_face_do_settings_mode(movement_event_t event, movement_
|
||||||
if (state->current_screen > 3) {
|
if (state->current_screen > 3) {
|
||||||
movement_request_tick_frequency(1);
|
movement_request_tick_frequency(1);
|
||||||
state->current_screen = 0;
|
state->current_screen = 0;
|
||||||
state->previous_date_time = 0xFFFFFFFF;
|
|
||||||
if (state->backup_register) watch_store_backup_data(state->settings.reg, state->backup_register);
|
if (state->backup_register) watch_store_backup_data(state->settings.reg, state->backup_register);
|
||||||
world_clock_face_do_display_mode(event, settings, state);
|
event.event_type = EVENT_ACTIVATE;
|
||||||
|
return world_clock_face_do_display_mode(event, settings, state);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
case EVENT_ALARM_BUTTON_DOWN:
|
||||||
|
|
280
movement/watch_faces/complication/astronomy_face.c
Normal file
280
movement/watch_faces/complication/astronomy_face.c
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "astronomy_face.h"
|
||||||
|
#include "watch_utility.h"
|
||||||
|
|
||||||
|
#if __EMSCRIPTEN__
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NUM_AVAILABLE_BODIES 9
|
||||||
|
|
||||||
|
static const char astronomy_available_celestial_bodies[NUM_AVAILABLE_BODIES] = {
|
||||||
|
ASTRO_BODY_SUN,
|
||||||
|
ASTRO_BODY_MERCURY,
|
||||||
|
ASTRO_BODY_VENUS,
|
||||||
|
ASTRO_BODY_MOON,
|
||||||
|
ASTRO_BODY_MARS,
|
||||||
|
ASTRO_BODY_JUPITER,
|
||||||
|
ASTRO_BODY_SATURN,
|
||||||
|
ASTRO_BODY_URANUS,
|
||||||
|
ASTRO_BODY_NEPTUNE
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char astronomy_celestial_body_names[NUM_AVAILABLE_BODIES][3] = {
|
||||||
|
"SO", // Sol
|
||||||
|
"ME", // Mercury
|
||||||
|
"VE", // Venus
|
||||||
|
"LU", // Moon (Luna)
|
||||||
|
"MA", // Mars
|
||||||
|
"JU", // Jupiter
|
||||||
|
"SA", // Saturn
|
||||||
|
"UR", // Uranus
|
||||||
|
"NE" // Neptune
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _astronomy_face_recalculate(movement_settings_t *settings, astronomy_state_t *state) {
|
||||||
|
#if __EMSCRIPTEN__
|
||||||
|
int16_t browser_lat = EM_ASM_INT({
|
||||||
|
return lat;
|
||||||
|
});
|
||||||
|
int16_t browser_lon = EM_ASM_INT({
|
||||||
|
return lon;
|
||||||
|
});
|
||||||
|
if ((watch_get_backup_data(1) == 0) && (browser_lat || browser_lon)) {
|
||||||
|
movement_location_t browser_loc;
|
||||||
|
browser_loc.bit.latitude = browser_lat;
|
||||||
|
browser_loc.bit.longitude = browser_lon;
|
||||||
|
watch_store_backup_data(browser_loc.reg, 1);
|
||||||
|
double lat = (double)browser_lat / 100.0;
|
||||||
|
double lon = (double)browser_lon / 100.0;
|
||||||
|
state->latitude_radians = astro_degrees_to_radians(lat);
|
||||||
|
state->longitude_radians = astro_degrees_to_radians(lon);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
watch_date_time date_time = watch_rtc_get_date_time();
|
||||||
|
uint32_t timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
|
||||||
|
date_time = watch_utility_date_time_from_unix_time(timestamp, 0);
|
||||||
|
double jd = astro_convert_date_to_julian_date(date_time.unit.year + WATCH_RTC_REFERENCE_YEAR, date_time.unit.month, date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
|
||||||
|
|
||||||
|
astro_equatorial_coordinates_t radec_precession = astro_get_ra_dec(jd, astronomy_available_celestial_bodies[state->active_body_index], state->latitude_radians, state->longitude_radians, true);
|
||||||
|
printf("\nParams to convert: %f %f %f %f %f\n",
|
||||||
|
jd,
|
||||||
|
astro_radians_to_degrees(state->latitude_radians),
|
||||||
|
astro_radians_to_degrees(state->longitude_radians),
|
||||||
|
astro_radians_to_degrees(radec_precession.right_ascension),
|
||||||
|
astro_radians_to_degrees(radec_precession.declination));
|
||||||
|
|
||||||
|
astro_horizontal_coordinates_t horiz = astro_ra_dec_to_alt_az(jd, state->latitude_radians, state->longitude_radians, radec_precession.right_ascension, radec_precession.declination);
|
||||||
|
astro_equatorial_coordinates_t radec = astro_get_ra_dec(jd, astronomy_available_celestial_bodies[state->active_body_index], state->latitude_radians, state->longitude_radians, false);
|
||||||
|
state->altitude = astro_radians_to_degrees(horiz.altitude);
|
||||||
|
state->azimuth = astro_radians_to_degrees(horiz.azimuth);
|
||||||
|
state->right_ascension = astro_radians_to_hms(radec.right_ascension);
|
||||||
|
state->declination = astro_radians_to_dms(radec.declination);
|
||||||
|
state->distance = radec.distance;
|
||||||
|
|
||||||
|
printf("Calculated coordinates for %s on %f: \n\tRA = %f / %2dh %2dm %2ds\n\tDec = %f / %3d° %3d' %3d\"\n\tAzi = %f\n\tAlt = %f\n\tDst = %f AU\n",
|
||||||
|
astronomy_celestial_body_names[state->active_body_index],
|
||||||
|
jd,
|
||||||
|
astro_radians_to_degrees(radec.right_ascension),
|
||||||
|
state->right_ascension.hours,
|
||||||
|
state->right_ascension.minutes,
|
||||||
|
state->right_ascension.seconds,
|
||||||
|
astro_radians_to_degrees(radec.declination),
|
||||||
|
state->declination.degrees,
|
||||||
|
state->declination.minutes,
|
||||||
|
state->declination.seconds,
|
||||||
|
state->altitude,
|
||||||
|
state->azimuth,
|
||||||
|
state->distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _astronomy_face_update(movement_event_t event, movement_settings_t *settings, astronomy_state_t *state) {
|
||||||
|
char buf[16];
|
||||||
|
switch (state->mode) {
|
||||||
|
case ASTRONOMY_MODE_SELECTING_BODY:
|
||||||
|
watch_clear_colon();
|
||||||
|
watch_display_string(" Astro", 4);
|
||||||
|
if (event.subsecond % 2) {
|
||||||
|
watch_display_string((char *)astronomy_celestial_body_names[state->active_body_index], 0);
|
||||||
|
} else {
|
||||||
|
watch_display_string(" ", 0);
|
||||||
|
}
|
||||||
|
if (event.subsecond == 0) {
|
||||||
|
watch_display_string(" ", 2);
|
||||||
|
switch (state->animation_state) {
|
||||||
|
case 0:
|
||||||
|
watch_set_pixel(0, 7);
|
||||||
|
watch_set_pixel(2, 6);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
watch_set_pixel(1, 7);
|
||||||
|
watch_set_pixel(2, 9);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
watch_set_pixel(2, 7);
|
||||||
|
watch_set_pixel(0, 9);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state->animation_state = (state->animation_state + 1) % 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ASTRONOMY_MODE_CALCULATING:
|
||||||
|
watch_clear_display();
|
||||||
|
// this takes a moment and locks the UI, flash C for "Calculating"
|
||||||
|
watch_start_character_blink('C', 100);
|
||||||
|
_astronomy_face_recalculate(settings, state);
|
||||||
|
watch_stop_blink();
|
||||||
|
state->mode = ASTRONOMY_MODE_DISPLAYING_ALT;
|
||||||
|
// fall through
|
||||||
|
case ASTRONOMY_MODE_DISPLAYING_ALT:
|
||||||
|
sprintf(buf, "%saL%6d", astronomy_celestial_body_names[state->active_body_index], (int16_t)round(state->altitude * 100));
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
break;
|
||||||
|
case ASTRONOMY_MODE_DISPLAYING_AZI:
|
||||||
|
sprintf(buf, "%saZ%6d", astronomy_celestial_body_names[state->active_body_index], (int16_t)round(state->azimuth * 100));
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
break;
|
||||||
|
case ASTRONOMY_MODE_DISPLAYING_RA:
|
||||||
|
watch_set_colon();
|
||||||
|
sprintf(buf, "ra H%02d%02d%02d", state->right_ascension.hours, state->right_ascension.minutes, state->right_ascension.seconds);
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
break;
|
||||||
|
case ASTRONOMY_MODE_DISPLAYING_DEC:
|
||||||
|
watch_clear_colon();
|
||||||
|
sprintf(buf, "de %3d%2d%2d", state->declination.degrees, state->declination.minutes, state->declination.seconds);
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
break;
|
||||||
|
case ASTRONOMY_MODE_DISPLAYING_DIST:
|
||||||
|
if (state->distance >= 0.00668456) {
|
||||||
|
// if >= 1,000,000 kilometers (all planets), we display distance in AU.
|
||||||
|
sprintf(buf, "diAU%6d", (uint16_t)round(state->distance * 100));
|
||||||
|
} else {
|
||||||
|
// otherwise distance in kilometers fits in 6 digits. This mode will only happen for Luna.
|
||||||
|
sprintf(buf, "di K%6ld", (uint32_t)round(state->distance * 149597871.0));
|
||||||
|
}
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
break;
|
||||||
|
case ASTRONOMY_MODE_NUM_MODES:
|
||||||
|
// this case does not happen, but we need it to silence a warning.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void astronomy_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||||
|
(void) settings;
|
||||||
|
(void) watch_face_index;
|
||||||
|
if (*context_ptr == NULL) {
|
||||||
|
*context_ptr = malloc(sizeof(astronomy_state_t));
|
||||||
|
memset(*context_ptr, 0, sizeof(astronomy_state_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void astronomy_face_activate(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
astronomy_state_t *state = (astronomy_state_t *)context;
|
||||||
|
movement_location_t movement_location = (movement_location_t) watch_get_backup_data(1);
|
||||||
|
int16_t lat_centi = (int16_t)movement_location.bit.latitude;
|
||||||
|
int16_t lon_centi = (int16_t)movement_location.bit.longitude;
|
||||||
|
double lat = (double)lat_centi / 100.0;
|
||||||
|
double lon = (double)lon_centi / 100.0;
|
||||||
|
state->latitude_radians = astro_degrees_to_radians(lat);
|
||||||
|
state->longitude_radians = astro_degrees_to_radians(lon);
|
||||||
|
|
||||||
|
movement_request_tick_frequency(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool astronomy_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||||
|
astronomy_state_t *state = (astronomy_state_t *)context;
|
||||||
|
|
||||||
|
switch (event.event_type) {
|
||||||
|
case EVENT_ACTIVATE:
|
||||||
|
case EVENT_TICK:
|
||||||
|
_astronomy_face_update(event, settings, state);
|
||||||
|
break;
|
||||||
|
case EVENT_MODE_BUTTON_UP:
|
||||||
|
// You shouldn't need to change this case; Mode almost always moves to the next watch face.
|
||||||
|
movement_move_to_next_face();
|
||||||
|
break;
|
||||||
|
case EVENT_LIGHT_BUTTON_UP:
|
||||||
|
// If you have other uses for the Light button, you can opt not to illuminate the LED for this event.
|
||||||
|
movement_illuminate_led();
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_BUTTON_UP:
|
||||||
|
switch (state->mode) {
|
||||||
|
case ASTRONOMY_MODE_SELECTING_BODY:
|
||||||
|
// advance to next celestial body (move to calculations with a long press)
|
||||||
|
state->active_body_index = (state->active_body_index + 1) % NUM_AVAILABLE_BODIES;
|
||||||
|
break;
|
||||||
|
case ASTRONOMY_MODE_CALCULATING:
|
||||||
|
// ignore button press during calculations
|
||||||
|
break;
|
||||||
|
case ASTRONOMY_MODE_DISPLAYING_DIST:
|
||||||
|
// at last mode, wrap around
|
||||||
|
state->mode = ASTRONOMY_MODE_DISPLAYING_ALT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// otherwise, advance to next mode
|
||||||
|
state->mode++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_astronomy_face_update(event, settings, state);
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_LONG_PRESS:
|
||||||
|
if (state->mode == ASTRONOMY_MODE_SELECTING_BODY) {
|
||||||
|
// celestial body selected! this triggers a calculation in the update method.
|
||||||
|
state->mode = ASTRONOMY_MODE_CALCULATING;
|
||||||
|
movement_request_tick_frequency(1);
|
||||||
|
_astronomy_face_update(event, settings, state);
|
||||||
|
} else if (state->mode != ASTRONOMY_MODE_CALCULATING) {
|
||||||
|
// in all modes except "doing a calculation", return to the selection screen.
|
||||||
|
state->mode = ASTRONOMY_MODE_SELECTING_BODY;
|
||||||
|
movement_request_tick_frequency(4);
|
||||||
|
_astronomy_face_update(event, settings, state);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_TIMEOUT:
|
||||||
|
movement_move_to_face(0);
|
||||||
|
break;
|
||||||
|
case EVENT_LOW_ENERGY_UPDATE:
|
||||||
|
// TODO?
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void astronomy_face_resign(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
astronomy_state_t *state = (astronomy_state_t *)context;
|
||||||
|
state->mode = ASTRONOMY_MODE_SELECTING_BODY;
|
||||||
|
}
|
68
movement/watch_faces/complication/astronomy_face.h
Normal file
68
movement/watch_faces/complication/astronomy_face.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 ASTRONOMY_FACE_H_
|
||||||
|
#define ASTRONOMY_FACE_H_
|
||||||
|
|
||||||
|
#include "movement.h"
|
||||||
|
#include "astrolib.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ASTRONOMY_MODE_SELECTING_BODY = 0,
|
||||||
|
ASTRONOMY_MODE_CALCULATING,
|
||||||
|
ASTRONOMY_MODE_DISPLAYING_ALT,
|
||||||
|
ASTRONOMY_MODE_DISPLAYING_AZI,
|
||||||
|
ASTRONOMY_MODE_DISPLAYING_RA,
|
||||||
|
ASTRONOMY_MODE_DISPLAYING_DEC,
|
||||||
|
ASTRONOMY_MODE_DISPLAYING_DIST,
|
||||||
|
ASTRONOMY_MODE_NUM_MODES
|
||||||
|
} astronomy_mode_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
astronomy_mode_t mode;
|
||||||
|
uint8_t active_body_index;
|
||||||
|
uint8_t animation_state;
|
||||||
|
double latitude_radians; // this is the user location
|
||||||
|
double longitude_radians; // but in radians
|
||||||
|
astro_angle_hms_t right_ascension;
|
||||||
|
astro_angle_dms_t declination;
|
||||||
|
double altitude; // in decimal degrees
|
||||||
|
double azimuth; // in decimal degrees
|
||||||
|
double distance; // in AU
|
||||||
|
} astronomy_state_t;
|
||||||
|
|
||||||
|
void astronomy_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||||
|
void astronomy_face_activate(movement_settings_t *settings, void *context);
|
||||||
|
bool astronomy_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||||
|
void astronomy_face_resign(movement_settings_t *settings, void *context);
|
||||||
|
|
||||||
|
#define astronomy_face ((const watch_face_t){ \
|
||||||
|
astronomy_face_setup, \
|
||||||
|
astronomy_face_activate, \
|
||||||
|
astronomy_face_loop, \
|
||||||
|
astronomy_face_resign, \
|
||||||
|
NULL, \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif // ASTRONOMY_FACE_H_
|
|
@ -35,14 +35,6 @@
|
||||||
#define DEFAULT_MINUTES 3
|
#define DEFAULT_MINUTES 3
|
||||||
|
|
||||||
|
|
||||||
static uint32_t offset_date_time(uint32_t now, int8_t hours, int8_t minutes, int8_t seconds) {
|
|
||||||
uint32_t new = now;
|
|
||||||
new += hours * 60 * 60;
|
|
||||||
new += minutes * 60;
|
|
||||||
new += seconds;
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int32_t get_tz_offset(movement_settings_t *settings) {
|
static inline int32_t get_tz_offset(movement_settings_t *settings) {
|
||||||
return movement_timezone_offsets[settings->bit.time_zone] * 60;
|
return movement_timezone_offsets[settings->bit.time_zone] * 60;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +44,7 @@ static void start(countdown_state_t *state, movement_settings_t *settings) {
|
||||||
|
|
||||||
state->mode = cd_running;
|
state->mode = cd_running;
|
||||||
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
|
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
|
||||||
state->target_ts = offset_date_time(state->now_ts, 0, state->minutes, state->seconds);
|
state->target_ts = watch_utility_offset_timestamp(state->now_ts, 0, state->minutes, state->seconds);
|
||||||
watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
|
watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
|
||||||
movement_schedule_background_task(target_dt);
|
movement_schedule_background_task(target_dt);
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
watch_set_indicator(WATCH_INDICATOR_BELL);
|
||||||
|
|
90
movement/watch_faces/complication/counter_face.c
Normal file
90
movement/watch_faces/complication/counter_face.c
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Shogo Okamoto
|
||||||
|
*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "counter_face.h"
|
||||||
|
#include "watch.h"
|
||||||
|
|
||||||
|
void counter_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||||
|
(void) settings;
|
||||||
|
(void) watch_face_index;
|
||||||
|
if (*context_ptr == NULL) {
|
||||||
|
*context_ptr = malloc(sizeof(counter_state_t));
|
||||||
|
memset(*context_ptr, 0, sizeof(counter_state_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void counter_face_activate(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
(void) context;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool counter_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
|
||||||
|
counter_state_t *state = (counter_state_t *)context;
|
||||||
|
|
||||||
|
switch (event.event_type) {
|
||||||
|
case EVENT_MODE_BUTTON_UP:
|
||||||
|
movement_move_to_next_face();
|
||||||
|
break;
|
||||||
|
case EVENT_LIGHT_BUTTON_DOWN:
|
||||||
|
movement_illuminate_led();
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_BUTTON_UP:
|
||||||
|
state->counter_idx++; // increment counter index
|
||||||
|
if (state->counter_idx>99) { //0-99
|
||||||
|
state->counter_idx=0;//reset counter index
|
||||||
|
}
|
||||||
|
print_counter(state);
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_LONG_PRESS:
|
||||||
|
state->counter_idx=0; // reset counter index
|
||||||
|
print_counter(state);
|
||||||
|
break;
|
||||||
|
case EVENT_ACTIVATE:
|
||||||
|
print_counter(state);
|
||||||
|
break;
|
||||||
|
case EVENT_TIMEOUT:
|
||||||
|
// ignore timeout
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print counter index at the center of display.
|
||||||
|
void print_counter(counter_state_t *state) {
|
||||||
|
char buf[14];
|
||||||
|
sprintf(buf, "CO %02d", state->counter_idx); // center of LCD display
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void counter_face_resign(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
(void) context;
|
||||||
|
}
|
51
movement/watch_faces/complication/counter_face.h
Normal file
51
movement/watch_faces/complication/counter_face.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Shogo Okamoto
|
||||||
|
*
|
||||||
|
* 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 COUNTER_FACE_H_
|
||||||
|
#define COUNTER_FACE_H_
|
||||||
|
|
||||||
|
#include "movement.h"
|
||||||
|
|
||||||
|
// Counter face is designed to count the number of running laps during excercises.
|
||||||
|
typedef struct {
|
||||||
|
uint8_t counter_idx;
|
||||||
|
} counter_state_t;
|
||||||
|
|
||||||
|
|
||||||
|
void counter_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||||
|
void counter_face_activate(movement_settings_t *settings, void *context);
|
||||||
|
bool counter_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||||
|
void counter_face_resign(movement_settings_t *settings, void *context);
|
||||||
|
|
||||||
|
void print_counter(counter_state_t *state);
|
||||||
|
|
||||||
|
#define counter_face ((const watch_face_t){ \
|
||||||
|
counter_face_setup, \
|
||||||
|
counter_face_activate, \
|
||||||
|
counter_face_loop, \
|
||||||
|
counter_face_resign, \
|
||||||
|
NULL, \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif // COUNTER_FACE_H_
|
|
@ -158,7 +158,7 @@ bool moon_phase_face_loop(movement_event_t event, movement_settings_t *settings,
|
||||||
case EVENT_MODE_BUTTON_UP:
|
case EVENT_MODE_BUTTON_UP:
|
||||||
movement_move_to_next_face();
|
movement_move_to_next_face();
|
||||||
break;
|
break;
|
||||||
case EVENT_LIGHT_BUTTON_UP:
|
case EVENT_LIGHT_BUTTON_DOWN:
|
||||||
movement_illuminate_led();
|
movement_illuminate_led();
|
||||||
break;
|
break;
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
case EVENT_ALARM_BUTTON_UP:
|
||||||
|
|
232
movement/watch_faces/complication/orrery_face.c
Normal file
232
movement/watch_faces/complication/orrery_face.c
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "orrery_face.h"
|
||||||
|
#include "watch.h"
|
||||||
|
#include "watch_utility.h"
|
||||||
|
#include "vsop87a_micro.h" // smaller size, less accurate
|
||||||
|
#include "vsop87a_milli.h"
|
||||||
|
#include "astrolib.h"
|
||||||
|
|
||||||
|
#define NUM_AVAILABLE_BODIES 9
|
||||||
|
|
||||||
|
static const char orrery_celestial_body_names[NUM_AVAILABLE_BODIES][3] = {
|
||||||
|
"ME", // Mercury
|
||||||
|
"VE", // Venus
|
||||||
|
"EA", // Earth
|
||||||
|
"LU", // Moon (Luna)
|
||||||
|
"MA", // Mars
|
||||||
|
"JU", // Jupiter
|
||||||
|
"SA", // Saturn
|
||||||
|
"UR", // Uranus
|
||||||
|
"NE" // Neptune
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _orrery_face_recalculate(movement_settings_t *settings, orrery_state_t *state) {
|
||||||
|
watch_date_time date_time = watch_rtc_get_date_time();
|
||||||
|
uint32_t timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
|
||||||
|
date_time = watch_utility_date_time_from_unix_time(timestamp, 0);
|
||||||
|
double jd = astro_convert_date_to_julian_date(date_time.unit.year + WATCH_RTC_REFERENCE_YEAR, date_time.unit.month, date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
|
||||||
|
double et = astro_convert_jd_to_julian_millenia_since_j2000(jd);
|
||||||
|
double r[3] = {0};
|
||||||
|
|
||||||
|
switch(state->active_body_index) {
|
||||||
|
case 0:
|
||||||
|
vsop87a_milli_getMercury(et, r);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
vsop87a_milli_getVenus(et, r);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
vsop87a_milli_getEarth(et, r);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
double earth[3];
|
||||||
|
double emb[3];
|
||||||
|
vsop87a_milli_getEarth(et, earth);
|
||||||
|
vsop87a_milli_getEmb(et, emb);
|
||||||
|
vsop87a_milli_getMoon(earth, emb, r);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
vsop87a_milli_getMars(et, r);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
vsop87a_milli_getJupiter(et, r);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
vsop87a_milli_getSaturn(et, r);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
vsop87a_milli_getUranus(et, r);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
vsop87a_milli_getNeptune(et, r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state->coords[0] = r[0];
|
||||||
|
state->coords[1] = r[1];
|
||||||
|
state->coords[2] = r[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _orrery_face_update(movement_event_t event, movement_settings_t *settings, orrery_state_t *state) {
|
||||||
|
char buf[11];
|
||||||
|
switch (state->mode) {
|
||||||
|
case ORRERY_MODE_SELECTING_BODY:
|
||||||
|
watch_display_string("Orrery", 4);
|
||||||
|
if (event.subsecond % 2) {
|
||||||
|
watch_display_string((char *)orrery_celestial_body_names[state->active_body_index], 0);
|
||||||
|
} else {
|
||||||
|
watch_display_string(" ", 0);
|
||||||
|
}
|
||||||
|
if (event.subsecond == 0) {
|
||||||
|
watch_display_string(" ", 2);
|
||||||
|
switch (state->animation_state) {
|
||||||
|
case 0:
|
||||||
|
watch_set_pixel(0, 7);
|
||||||
|
watch_set_pixel(2, 6);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
watch_set_pixel(1, 7);
|
||||||
|
watch_set_pixel(2, 9);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
watch_set_pixel(2, 7);
|
||||||
|
watch_set_pixel(0, 9);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state->animation_state = (state->animation_state + 1) % 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ORRERY_MODE_CALCULATING:
|
||||||
|
watch_clear_display();
|
||||||
|
// this takes a moment and locks the UI, flash C for "Calculating"
|
||||||
|
watch_start_character_blink('C', 100);
|
||||||
|
_orrery_face_recalculate(settings, state);
|
||||||
|
watch_stop_blink();
|
||||||
|
state->mode = ORRERY_MODE_DISPLAYING_X;
|
||||||
|
// fall through
|
||||||
|
case ORRERY_MODE_DISPLAYING_X:
|
||||||
|
sprintf(buf, "%s X%6d", orrery_celestial_body_names[state->active_body_index], (int16_t)round(state->coords[0] * 100));
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
break;
|
||||||
|
case ORRERY_MODE_DISPLAYING_Y:
|
||||||
|
sprintf(buf, "%s Y%6d", orrery_celestial_body_names[state->active_body_index], (int16_t)round(state->coords[1] * 100));
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
break;
|
||||||
|
case ORRERY_MODE_DISPLAYING_Z:
|
||||||
|
sprintf(buf, "%s Z%6d", orrery_celestial_body_names[state->active_body_index], (int16_t)round(state->coords[2] * 100));
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
break;
|
||||||
|
case ORRERY_MODE_NUM_MODES:
|
||||||
|
// this case does not happen, but we need it to silence a warning.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void orrery_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||||
|
(void) settings;
|
||||||
|
(void) watch_face_index;
|
||||||
|
if (*context_ptr == NULL) {
|
||||||
|
*context_ptr = malloc(sizeof(orrery_state_t));
|
||||||
|
memset(*context_ptr, 0, sizeof(orrery_state_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void orrery_face_activate(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
(void) context;
|
||||||
|
movement_request_tick_frequency(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool orrery_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
orrery_state_t *state = (orrery_state_t *)context;
|
||||||
|
|
||||||
|
switch (event.event_type) {
|
||||||
|
case EVENT_ACTIVATE:
|
||||||
|
case EVENT_TICK:
|
||||||
|
_orrery_face_update(event, settings, state);
|
||||||
|
break;
|
||||||
|
case EVENT_MODE_BUTTON_UP:
|
||||||
|
movement_move_to_next_face();
|
||||||
|
break;
|
||||||
|
case EVENT_LIGHT_BUTTON_DOWN:
|
||||||
|
movement_illuminate_led();
|
||||||
|
break;
|
||||||
|
case EVENT_LIGHT_BUTTON_UP:
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_BUTTON_UP:
|
||||||
|
switch (state->mode) {
|
||||||
|
case ORRERY_MODE_SELECTING_BODY:
|
||||||
|
// advance to next celestial body (move to calculations with a long press)
|
||||||
|
state->active_body_index = (state->active_body_index + 1) % NUM_AVAILABLE_BODIES;
|
||||||
|
break;
|
||||||
|
case ORRERY_MODE_CALCULATING:
|
||||||
|
// ignore button press during calculations
|
||||||
|
break;
|
||||||
|
case ORRERY_MODE_DISPLAYING_Z:
|
||||||
|
// at last mode, wrap around
|
||||||
|
state->mode = ORRERY_MODE_DISPLAYING_X;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// otherwise, advance to next mode
|
||||||
|
state->mode++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_orrery_face_update(event, settings, state);
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_LONG_PRESS:
|
||||||
|
if (state->mode == ORRERY_MODE_SELECTING_BODY) {
|
||||||
|
// celestial body selected! this triggers a calculation in the update method.
|
||||||
|
state->mode = ORRERY_MODE_CALCULATING;
|
||||||
|
movement_request_tick_frequency(1);
|
||||||
|
_orrery_face_update(event, settings, state);
|
||||||
|
} else if (state->mode != ORRERY_MODE_CALCULATING) {
|
||||||
|
// in all modes except "doing a calculation", return to the selection screen.
|
||||||
|
state->mode = ORRERY_MODE_SELECTING_BODY;
|
||||||
|
movement_request_tick_frequency(4);
|
||||||
|
_orrery_face_update(event, settings, state);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_TIMEOUT:
|
||||||
|
movement_move_to_face(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void orrery_face_resign(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
orrery_state_t *state = (orrery_state_t *)context;
|
||||||
|
state->mode = ORRERY_MODE_SELECTING_BODY;
|
||||||
|
}
|
59
movement/watch_faces/complication/orrery_face.h
Normal file
59
movement/watch_faces/complication/orrery_face.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 ORRERY_FACE_H_
|
||||||
|
#define ORRERY_FACE_H_
|
||||||
|
|
||||||
|
#include "movement.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ORRERY_MODE_SELECTING_BODY = 0,
|
||||||
|
ORRERY_MODE_CALCULATING,
|
||||||
|
ORRERY_MODE_DISPLAYING_X,
|
||||||
|
ORRERY_MODE_DISPLAYING_Y,
|
||||||
|
ORRERY_MODE_DISPLAYING_Z,
|
||||||
|
ORRERY_MODE_NUM_MODES
|
||||||
|
} orrery_mode_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
orrery_mode_t mode;
|
||||||
|
uint8_t active_body_index;
|
||||||
|
double coords[3];
|
||||||
|
uint8_t animation_state;
|
||||||
|
} orrery_state_t;
|
||||||
|
|
||||||
|
void orrery_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||||
|
void orrery_face_activate(movement_settings_t *settings, void *context);
|
||||||
|
bool orrery_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||||
|
void orrery_face_resign(movement_settings_t *settings, void *context);
|
||||||
|
|
||||||
|
#define orrery_face ((const watch_face_t){ \
|
||||||
|
orrery_face_setup, \
|
||||||
|
orrery_face_activate, \
|
||||||
|
orrery_face_loop, \
|
||||||
|
orrery_face_resign, \
|
||||||
|
NULL, \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif // ORRERY_FACE_H_
|
|
@ -73,7 +73,7 @@ bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings,
|
||||||
watch_display_string(" Alarn", 4);
|
watch_display_string(" Alarn", 4);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
watch_display_string("+ Count ", 0);
|
watch_display_string("* Count ", 0);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
watch_display_string(" 30Beats ", 0);
|
watch_display_string(" 30Beats ", 0);
|
||||||
|
|
|
@ -188,10 +188,10 @@ static void _sunrise_sunset_face_update_settings_display(movement_event_t event,
|
||||||
|
|
||||||
switch (state->page) {
|
switch (state->page) {
|
||||||
case 1:
|
case 1:
|
||||||
sprintf(buf, "LA %c %04d", state->working_latitude.sign ? '-' : 'F', abs(_sunrise_sunset_face_latlon_from_struct(state->working_latitude))); // F looks sorta like a plus sign in position 1
|
sprintf(buf, "LA %c %04d", state->working_latitude.sign ? '-' : '+', abs(_sunrise_sunset_face_latlon_from_struct(state->working_latitude)));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sprintf(buf, "LO %c%05d", state->working_longitude.sign ? '-' : 'F', abs(_sunrise_sunset_face_latlon_from_struct(state->working_longitude)));
|
sprintf(buf, "LO %c%05d", state->working_longitude.sign ? '-' : '+', abs(_sunrise_sunset_face_latlon_from_struct(state->working_longitude)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (event.subsecond % 2) {
|
if (event.subsecond % 2) {
|
||||||
|
|
191
movement/watch_faces/complication/tomato_face.c
Normal file
191
movement/watch_faces/complication/tomato_face.c
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Wesley Ellis
|
||||||
|
*
|
||||||
|
* 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 NONINFtomato_ringEMENT. 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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "tomato_face.h"
|
||||||
|
#include "watch_utility.h"
|
||||||
|
|
||||||
|
static uint8_t focus_min = 25;
|
||||||
|
static uint8_t break_min = 5;
|
||||||
|
|
||||||
|
static inline int32_t get_tz_offset(movement_settings_t *settings) {
|
||||||
|
return movement_timezone_offsets[settings->bit.time_zone] * 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t get_length(tomato_state_t *state) {
|
||||||
|
uint8_t length;
|
||||||
|
if (state->kind == tomato_focus) {
|
||||||
|
length = focus_min;
|
||||||
|
} else {
|
||||||
|
length = break_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tomato_start(tomato_state_t *state, movement_settings_t *settings) {
|
||||||
|
watch_date_time now = watch_rtc_get_date_time();
|
||||||
|
int8_t length = (int8_t) get_length(state);
|
||||||
|
|
||||||
|
state->mode = tomato_run;
|
||||||
|
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
|
||||||
|
state->target_ts = watch_utility_offset_timestamp(state->now_ts, 0, length, 0);
|
||||||
|
watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
|
||||||
|
movement_schedule_background_task(target_dt);
|
||||||
|
watch_set_indicator(WATCH_INDICATOR_BELL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tomato_draw(tomato_state_t *state) {
|
||||||
|
char buf[16];
|
||||||
|
|
||||||
|
uint32_t delta;
|
||||||
|
div_t result;
|
||||||
|
uint8_t min = 0;
|
||||||
|
uint8_t sec = 0;
|
||||||
|
char kind;
|
||||||
|
|
||||||
|
if (state->kind == tomato_break) {
|
||||||
|
kind = 'b';
|
||||||
|
} else {
|
||||||
|
kind = 'f';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state->mode) {
|
||||||
|
case tomato_run:
|
||||||
|
delta = state->target_ts - state->now_ts;
|
||||||
|
result = div(delta, 60);
|
||||||
|
min = result.quot;
|
||||||
|
sec = result.rem;
|
||||||
|
break;
|
||||||
|
case tomato_ready:
|
||||||
|
min = get_length(state);
|
||||||
|
sec = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sprintf(buf, "TO %c%2d%02d%2d", kind, min, sec, state->done_count);
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tomato_reset(tomato_state_t *state) {
|
||||||
|
state->mode = tomato_ready;
|
||||||
|
movement_cancel_background_task();
|
||||||
|
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tomato_ring(tomato_state_t *state) {
|
||||||
|
movement_play_signal();
|
||||||
|
tomato_reset(state);
|
||||||
|
if (state->kind == tomato_focus) {
|
||||||
|
state->kind = tomato_break;
|
||||||
|
state->done_count++;
|
||||||
|
} else {
|
||||||
|
state->kind = tomato_focus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tomato_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||||
|
(void) settings;
|
||||||
|
(void) watch_face_index;
|
||||||
|
|
||||||
|
if (*context_ptr == NULL) {
|
||||||
|
*context_ptr = malloc(sizeof(tomato_state_t));
|
||||||
|
tomato_state_t *state = (tomato_state_t*)*context_ptr;
|
||||||
|
memset(*context_ptr, 0, sizeof(tomato_state_t));
|
||||||
|
state->mode=tomato_ready;
|
||||||
|
state->kind= tomato_focus;
|
||||||
|
state->done_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tomato_face_activate(movement_settings_t *settings, void *context) {
|
||||||
|
tomato_state_t *state = (tomato_state_t *)context;
|
||||||
|
if (state->mode == tomato_run) {
|
||||||
|
watch_date_time now = watch_rtc_get_date_time();
|
||||||
|
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
|
||||||
|
}
|
||||||
|
watch_set_colon();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tomato_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||||
|
tomato_state_t *state = (tomato_state_t *)context;
|
||||||
|
|
||||||
|
switch (event.event_type) {
|
||||||
|
case EVENT_ACTIVATE:
|
||||||
|
tomato_draw(state);
|
||||||
|
break;
|
||||||
|
case EVENT_TICK:
|
||||||
|
if (state->mode == tomato_run) {
|
||||||
|
state->now_ts++;
|
||||||
|
}
|
||||||
|
tomato_draw(state);
|
||||||
|
break;
|
||||||
|
case EVENT_MODE_BUTTON_UP:
|
||||||
|
movement_move_to_next_face();
|
||||||
|
break;
|
||||||
|
case EVENT_LIGHT_BUTTON_UP:
|
||||||
|
movement_illuminate_led();
|
||||||
|
if (state->mode == tomato_ready) {
|
||||||
|
if (state->kind == tomato_break) {
|
||||||
|
state->kind = tomato_focus;
|
||||||
|
} else {
|
||||||
|
state->kind = tomato_break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tomato_draw(state);
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_BUTTON_UP:
|
||||||
|
switch(state->mode) {
|
||||||
|
case tomato_run:
|
||||||
|
tomato_reset(state);
|
||||||
|
break;
|
||||||
|
case tomato_ready:
|
||||||
|
tomato_start(state, settings);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tomato_draw(state);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_LONG_PRESS:
|
||||||
|
state->done_count = 0;
|
||||||
|
break;
|
||||||
|
case EVENT_BACKGROUND_TASK:
|
||||||
|
tomato_ring(state);
|
||||||
|
tomato_draw(state);
|
||||||
|
break;
|
||||||
|
case EVENT_TIMEOUT:
|
||||||
|
movement_move_to_face(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tomato_face_resign(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
(void) context;
|
||||||
|
}
|
||||||
|
|
63
movement/watch_faces/complication/tomato_face.h
Normal file
63
movement/watch_faces/complication/tomato_face.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Wesley Ellis
|
||||||
|
*
|
||||||
|
* 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 TOMATO_FACE_H_
|
||||||
|
#define TOMATO_FACE_H_
|
||||||
|
|
||||||
|
#include "movement.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
tomato_ready,
|
||||||
|
tomato_run,
|
||||||
|
// to_pause, // TODO implement pausing
|
||||||
|
} tomato_mode;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
tomato_break,
|
||||||
|
tomato_focus,
|
||||||
|
} tomato_kind;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t target_ts;
|
||||||
|
uint32_t now_ts;
|
||||||
|
tomato_mode mode;
|
||||||
|
tomato_kind kind;
|
||||||
|
uint8_t done_count;
|
||||||
|
} tomato_state_t;
|
||||||
|
|
||||||
|
void tomato_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||||
|
void tomato_face_activate(movement_settings_t *settings, void *context);
|
||||||
|
bool tomato_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||||
|
void tomato_face_resign(movement_settings_t *settings, void *context);
|
||||||
|
|
||||||
|
#define tomato_face ((const watch_face_t){ \
|
||||||
|
tomato_face_setup, \
|
||||||
|
tomato_face_activate, \
|
||||||
|
tomato_face_loop, \
|
||||||
|
tomato_face_resign, \
|
||||||
|
NULL, \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif // TOMATO_FACE_H_
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "lis2dh_logging_face.h"
|
#include "lis2dw_logging_face.h"
|
||||||
#include "lis2dh.h"
|
#include "lis2dw.h"
|
||||||
#include "watch.h"
|
#include "watch.h"
|
||||||
|
|
||||||
// This watch face is just for testing; if we want to build accelerometer support, it will likely have to be part of Movement itself.
|
// This watch face is just for testing; if we want to build accelerometer support, it will likely have to be part of Movement itself.
|
||||||
|
@ -36,14 +36,14 @@
|
||||||
// Pressing the alarm button enters the log mode, where the main display shows the number of interrupts detected in each of the last
|
// Pressing the alarm button enters the log mode, where the main display shows the number of interrupts detected in each of the last
|
||||||
// 24 hours (the hour is shown in the top right digit and AM/PM indicator, if the clock is set to 12 hour mode)
|
// 24 hours (the hour is shown in the top right digit and AM/PM indicator, if the clock is set to 12 hour mode)
|
||||||
|
|
||||||
static void _lis2dh_logging_face_update_display(movement_settings_t *settings, lis2dh_logger_state_t *logger_state, lis2dh_interrupt_state interrupt_state) {
|
static void _lis2dw_logging_face_update_display(movement_settings_t *settings, lis2dw_logger_state_t *logger_state, lis2dw_wakeup_source wakeup_source) {
|
||||||
char buf[14];
|
char buf[14];
|
||||||
char time_indication_character;
|
char time_indication_character;
|
||||||
int8_t pos;
|
int8_t pos;
|
||||||
watch_date_time date_time;
|
watch_date_time date_time;
|
||||||
|
|
||||||
if (logger_state->log_ticks) {
|
if (logger_state->log_ticks) {
|
||||||
pos = (logger_state->data_points - 1 - logger_state->display_index) % LIS2DH_LOGGING_NUM_DATA_POINTS;
|
pos = (logger_state->data_points - 1 - logger_state->display_index) % LIS2DW_LOGGING_NUM_DATA_POINTS;
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
watch_clear_colon();
|
watch_clear_colon();
|
||||||
sprintf(buf, "NO data ");
|
sprintf(buf, "NO data ");
|
||||||
|
@ -80,9 +80,9 @@ static void _lis2dh_logging_face_update_display(movement_settings_t *settings, l
|
||||||
if ((59 - date_time.unit.second) < 10) time_indication_character = '0' + (59 - date_time.unit.second);
|
if ((59 - date_time.unit.second) < 10) time_indication_character = '0' + (59 - date_time.unit.second);
|
||||||
else time_indication_character = (date_time.unit.second % 2) ? 'i' : '_';
|
else time_indication_character = (date_time.unit.second % 2) ? 'i' : '_';
|
||||||
sprintf(buf, "%c%c%c%c%2d%2d%2d",
|
sprintf(buf, "%c%c%c%c%2d%2d%2d",
|
||||||
(interrupt_state & LIS2DH_INTERRUPT_STATE_Y_HIGH) ? 'Y' : ' ',
|
(wakeup_source & LIS2DW_WAKEUP_SRC_WAKEUP_Y) ? 'Y' : ' ',
|
||||||
(interrupt_state & LIS2DH_INTERRUPT_STATE_X_HIGH) ? 'X' : ' ',
|
(wakeup_source & LIS2DW_WAKEUP_SRC_WAKEUP_X) ? 'X' : ' ',
|
||||||
(interrupt_state & LIS2DH_INTERRUPT_STATE_Z_HIGH) ? 'Z' : ' ',
|
(wakeup_source & LIS2DW_WAKEUP_SRC_WAKEUP_Z) ? 'Z' : ' ',
|
||||||
time_indication_character,
|
time_indication_character,
|
||||||
logger_state->interrupts[0],
|
logger_state->interrupts[0],
|
||||||
logger_state->interrupts[1],
|
logger_state->interrupts[1],
|
||||||
|
@ -91,7 +91,7 @@ static void _lis2dh_logging_face_update_display(movement_settings_t *settings, l
|
||||||
watch_display_string(buf, 0);
|
watch_display_string(buf, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _lis2dh_logging_face_log_data(lis2dh_logger_state_t *logger_state) {
|
static void _lis2dw_logging_face_log_data(lis2dw_logger_state_t *logger_state) {
|
||||||
watch_date_time date_time = watch_rtc_get_date_time();
|
watch_date_time date_time = watch_rtc_get_date_time();
|
||||||
// we get this call 15 minutes late; i.e. at 6:15 we're logging events for 6:00.
|
// we get this call 15 minutes late; i.e. at 6:15 we're logging events for 6:00.
|
||||||
// so: if we're at the top of the hour, roll the hour back too (7:00 task logs data for 6:45)
|
// so: if we're at the top of the hour, roll the hour back too (7:00 task logs data for 6:45)
|
||||||
|
@ -100,7 +100,7 @@ static void _lis2dh_logging_face_log_data(lis2dh_logger_state_t *logger_state) {
|
||||||
// // then roll the minute back.
|
// // then roll the minute back.
|
||||||
date_time.unit.minute = (date_time.unit.minute + 45) % 60;
|
date_time.unit.minute = (date_time.unit.minute + 45) % 60;
|
||||||
|
|
||||||
size_t pos = logger_state->data_points % LIS2DH_LOGGING_NUM_DATA_POINTS;
|
size_t pos = logger_state->data_points % LIS2DW_LOGGING_NUM_DATA_POINTS;
|
||||||
logger_state->data[pos].timestamp.reg = date_time.reg;
|
logger_state->data[pos].timestamp.reg = date_time.reg;
|
||||||
logger_state->data[pos].x_interrupts = logger_state->x_interrupts_this_hour;
|
logger_state->data[pos].x_interrupts = logger_state->x_interrupts_this_hour;
|
||||||
logger_state->data[pos].y_interrupts = logger_state->y_interrupts_this_hour;
|
logger_state->data[pos].y_interrupts = logger_state->y_interrupts_this_hour;
|
||||||
|
@ -111,28 +111,25 @@ static void _lis2dh_logging_face_log_data(lis2dh_logger_state_t *logger_state) {
|
||||||
logger_state->z_interrupts_this_hour = 0;
|
logger_state->z_interrupts_this_hour = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lis2dh_logging_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
void lis2dw_logging_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||||
(void) settings;
|
(void) settings;
|
||||||
(void) watch_face_index;
|
(void) watch_face_index;
|
||||||
if (*context_ptr == NULL) {
|
if (*context_ptr == NULL) {
|
||||||
*context_ptr = malloc(sizeof(lis2dh_logger_state_t));
|
*context_ptr = malloc(sizeof(lis2dw_logger_state_t));
|
||||||
memset(*context_ptr, 0, sizeof(lis2dh_logger_state_t));
|
memset(*context_ptr, 0, sizeof(lis2dw_logger_state_t));
|
||||||
gpio_set_pin_direction(A0, GPIO_DIRECTION_OUT);
|
|
||||||
gpio_set_pin_function(A0, GPIO_PIN_FUNCTION_OFF);
|
|
||||||
gpio_set_pin_level(A0, true);
|
|
||||||
watch_enable_i2c();
|
watch_enable_i2c();
|
||||||
lis2dh_begin();
|
lis2dw_begin();
|
||||||
lis2dh_set_data_rate(LIS2DH_DATA_RATE_10_HZ);
|
lis2dw_set_low_power_mode(LIS2DW_LP_MODE_2); // lowest power 14-bit mode, 25 Hz is 3.5 µA @ 1.8V w/ low noise, 3µA without
|
||||||
lis2dh_configure_aoi_int1(
|
lis2dw_set_low_noise_mode(true); // consumes a little more power
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_OR |
|
lis2dw_set_range(LIS2DW_CTRL6_VAL_RANGE_4G);
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_X_HIGH_ENABLE |
|
lis2dw_set_data_rate(LIS2DW_DATA_RATE_25_HZ); // is this enough for training?
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_Y_HIGH_ENABLE |
|
// threshold is 1/64th of full scale, so for a FS of ±4G this is 1.25G
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_Z_HIGH_ENABLE, 96, 0, true);
|
lis2dw_configure_wakeup_int1(10, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lis2dh_logging_face_activate(movement_settings_t *settings, void *context) {
|
void lis2dw_logging_face_activate(movement_settings_t *settings, void *context) {
|
||||||
lis2dh_logger_state_t *logger_state = (lis2dh_logger_state_t *)context;
|
lis2dw_logger_state_t *logger_state = (lis2dw_logger_state_t *)context;
|
||||||
// force two settings: never enter low energy mode, and always snap back to screen 0.
|
// force two settings: never enter low energy mode, and always snap back to screen 0.
|
||||||
// this assumes the accelerometer face is first in the watch_faces list.
|
// this assumes the accelerometer face is first in the watch_faces list.
|
||||||
settings->bit.le_interval = 0;
|
settings->bit.le_interval = 0;
|
||||||
|
@ -140,12 +137,13 @@ void lis2dh_logging_face_activate(movement_settings_t *settings, void *context)
|
||||||
|
|
||||||
logger_state->display_index = 0;
|
logger_state->display_index = 0;
|
||||||
logger_state->log_ticks = 0;
|
logger_state->log_ticks = 0;
|
||||||
watch_enable_digital_input(A1);
|
watch_enable_digital_input(A0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lis2dh_logging_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
bool lis2dw_logging_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||||
lis2dh_logger_state_t *logger_state = (lis2dh_logger_state_t *)context;
|
lis2dw_logger_state_t *logger_state = (lis2dw_logger_state_t *)context;
|
||||||
lis2dh_interrupt_state interrupt_state = 0;
|
lis2dw_wakeup_source wakeup_source = 0;
|
||||||
|
lis2dw_interrupt_source interrupt_source = 0;
|
||||||
|
|
||||||
switch (event.event_type) {
|
switch (event.event_type) {
|
||||||
case EVENT_MODE_BUTTON_UP:
|
case EVENT_MODE_BUTTON_UP:
|
||||||
|
@ -157,13 +155,13 @@ bool lis2dh_logging_face_loop(movement_event_t event, movement_settings_t *setti
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
case EVENT_LIGHT_BUTTON_DOWN:
|
||||||
logger_state->axis_index = (logger_state->axis_index + 1) % 4;
|
logger_state->axis_index = (logger_state->axis_index + 1) % 4;
|
||||||
logger_state->log_ticks = 255;
|
logger_state->log_ticks = 255;
|
||||||
_lis2dh_logging_face_update_display(settings, logger_state, interrupt_state);
|
_lis2dw_logging_face_update_display(settings, logger_state, wakeup_source);
|
||||||
break;
|
break;
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
case EVENT_ALARM_BUTTON_UP:
|
||||||
if (logger_state->log_ticks) logger_state->display_index = (logger_state->display_index + 1) % LIS2DH_LOGGING_NUM_DATA_POINTS;
|
if (logger_state->log_ticks) logger_state->display_index = (logger_state->display_index + 1) % LIS2DW_LOGGING_NUM_DATA_POINTS;
|
||||||
logger_state->log_ticks = 255;
|
logger_state->log_ticks = 255;
|
||||||
logger_state->axis_index = 0;
|
logger_state->axis_index = 0;
|
||||||
_lis2dh_logging_face_update_display(settings, logger_state, interrupt_state);
|
_lis2dw_logging_face_update_display(settings, logger_state, wakeup_source);
|
||||||
break;
|
break;
|
||||||
case EVENT_ACTIVATE:
|
case EVENT_ACTIVATE:
|
||||||
case EVENT_TICK:
|
case EVENT_TICK:
|
||||||
|
@ -172,20 +170,21 @@ bool lis2dh_logging_face_loop(movement_event_t event, movement_settings_t *setti
|
||||||
} else {
|
} else {
|
||||||
logger_state->display_index = 0;
|
logger_state->display_index = 0;
|
||||||
}
|
}
|
||||||
if (watch_get_pin_level(A1)) {
|
interrupt_source = lis2dw_get_interrupt_source();
|
||||||
|
if (interrupt_source) {
|
||||||
watch_set_indicator(WATCH_INDICATOR_SIGNAL);
|
watch_set_indicator(WATCH_INDICATOR_SIGNAL);
|
||||||
interrupt_state = lis2dh_get_int1_state();
|
wakeup_source = lis2dw_get_wakeup_source();
|
||||||
logger_state->interrupts[0]++;
|
logger_state->interrupts[0]++;
|
||||||
if (interrupt_state & LIS2DH_INTERRUPT_STATE_X_HIGH) logger_state->x_interrupts_this_hour++;
|
if (wakeup_source & LIS2DW_WAKEUP_SRC_WAKEUP_X) logger_state->x_interrupts_this_hour++;
|
||||||
if (interrupt_state & LIS2DH_INTERRUPT_STATE_Y_HIGH) logger_state->y_interrupts_this_hour++;
|
if (wakeup_source & LIS2DW_WAKEUP_SRC_WAKEUP_Y) logger_state->y_interrupts_this_hour++;
|
||||||
if (interrupt_state & LIS2DH_INTERRUPT_STATE_Z_HIGH) logger_state->z_interrupts_this_hour++;
|
if (wakeup_source & LIS2DW_WAKEUP_SRC_WAKEUP_Z) logger_state->z_interrupts_this_hour++;
|
||||||
} else {
|
} else {
|
||||||
watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
|
watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
|
||||||
}
|
}
|
||||||
_lis2dh_logging_face_update_display(settings, logger_state, interrupt_state);
|
_lis2dw_logging_face_update_display(settings, logger_state, wakeup_source);
|
||||||
break;
|
break;
|
||||||
case EVENT_BACKGROUND_TASK:
|
case EVENT_BACKGROUND_TASK:
|
||||||
_lis2dh_logging_face_log_data(logger_state);
|
_lis2dw_logging_face_log_data(logger_state);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -194,15 +193,15 @@ bool lis2dh_logging_face_loop(movement_event_t event, movement_settings_t *setti
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lis2dh_logging_face_resign(movement_settings_t *settings, void *context) {
|
void lis2dw_logging_face_resign(movement_settings_t *settings, void *context) {
|
||||||
(void) settings;
|
(void) settings;
|
||||||
(void) context;
|
(void) context;
|
||||||
watch_disable_digital_input(A1);
|
watch_disable_digital_input(A0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lis2dh_logging_face_wants_background_task(movement_settings_t *settings, void *context) {
|
bool lis2dw_logging_face_wants_background_task(movement_settings_t *settings, void *context) {
|
||||||
(void) settings;
|
(void) settings;
|
||||||
lis2dh_logger_state_t *logger_state = (lis2dh_logger_state_t *)context;
|
lis2dw_logger_state_t *logger_state = (lis2dw_logger_state_t *)context;
|
||||||
watch_date_time date_time = watch_rtc_get_date_time();
|
watch_date_time date_time = watch_rtc_get_date_time();
|
||||||
|
|
||||||
// this is kind of an abuse of the API, but, let's use the 1 minute tick to shift all our data over.
|
// this is kind of an abuse of the API, but, let's use the 1 minute tick to shift all our data over.
|
|
@ -22,20 +22,20 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LIS2DH_LOGGING_FACE_H_
|
#ifndef LIS2DW_LOGGING_FACE_H_
|
||||||
#define LIS2DH_LOGGING_FACE_H_
|
#define LIS2DW_LOGGING_FACE_H_
|
||||||
|
|
||||||
#include "movement.h"
|
#include "movement.h"
|
||||||
#include "watch.h"
|
#include "watch.h"
|
||||||
|
|
||||||
#define LIS2DH_LOGGING_NUM_DATA_POINTS (96)
|
#define LIS2DW_LOGGING_NUM_DATA_POINTS (96)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
watch_date_time timestamp;
|
watch_date_time timestamp;
|
||||||
uint32_t x_interrupts;
|
uint32_t x_interrupts;
|
||||||
uint32_t y_interrupts;
|
uint32_t y_interrupts;
|
||||||
uint32_t z_interrupts;
|
uint32_t z_interrupts;
|
||||||
} lis2dh_logger_data_point_t;
|
} lis2dw_logger_data_point_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t display_index; // the index we are displaying on screen
|
uint8_t display_index; // the index we are displaying on screen
|
||||||
|
@ -46,21 +46,21 @@ typedef struct {
|
||||||
uint32_t x_interrupts_this_hour; // the number of interrupts we have logged in the last hour
|
uint32_t x_interrupts_this_hour; // the number of interrupts we have logged in the last hour
|
||||||
uint32_t y_interrupts_this_hour; // the number of interrupts we have logged in the last hour
|
uint32_t y_interrupts_this_hour; // the number of interrupts we have logged in the last hour
|
||||||
uint32_t z_interrupts_this_hour; // the number of interrupts we have logged in the last hour
|
uint32_t z_interrupts_this_hour; // the number of interrupts we have logged in the last hour
|
||||||
lis2dh_logger_data_point_t data[LIS2DH_LOGGING_NUM_DATA_POINTS];
|
lis2dw_logger_data_point_t data[LIS2DW_LOGGING_NUM_DATA_POINTS];
|
||||||
} lis2dh_logger_state_t;
|
} lis2dw_logger_state_t;
|
||||||
|
|
||||||
void lis2dh_logging_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
void lis2dw_logging_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||||
void lis2dh_logging_face_activate(movement_settings_t *settings, void *context);
|
void lis2dw_logging_face_activate(movement_settings_t *settings, void *context);
|
||||||
bool lis2dh_logging_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
bool lis2dw_logging_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||||
void lis2dh_logging_face_resign(movement_settings_t *settings, void *context);
|
void lis2dw_logging_face_resign(movement_settings_t *settings, void *context);
|
||||||
bool lis2dh_logging_face_wants_background_task(movement_settings_t *settings, void *context);
|
bool lis2dw_logging_face_wants_background_task(movement_settings_t *settings, void *context);
|
||||||
|
|
||||||
#define lis2dh_logging_face ((const watch_face_t){ \
|
#define lis2dw_logging_face ((const watch_face_t){ \
|
||||||
lis2dh_logging_face_setup, \
|
lis2dw_logging_face_setup, \
|
||||||
lis2dh_logging_face_activate, \
|
lis2dw_logging_face_activate, \
|
||||||
lis2dh_logging_face_loop, \
|
lis2dw_logging_face_loop, \
|
||||||
lis2dh_logging_face_resign, \
|
lis2dw_logging_face_resign, \
|
||||||
lis2dh_logging_face_wants_background_task, \
|
lis2dw_logging_face_wants_background_task, \
|
||||||
})
|
})
|
||||||
|
|
||||||
#endif // LIS2DH_LOGGING_FACE_H_
|
#endif // LIS2DW_LOGGING_FACE_H_
|
|
@ -29,7 +29,11 @@
|
||||||
|
|
||||||
static void _voltage_face_update_display(void) {
|
static void _voltage_face_update_display(void) {
|
||||||
char buf[14];
|
char buf[14];
|
||||||
|
|
||||||
|
watch_enable_adc();
|
||||||
float voltage = (float)watch_get_vcc_voltage() / 1000.0;
|
float voltage = (float)watch_get_vcc_voltage() / 1000.0;
|
||||||
|
watch_disable_adc();
|
||||||
|
|
||||||
sprintf(buf, "BA %4.2f V", voltage);
|
sprintf(buf, "BA %4.2f V", voltage);
|
||||||
// printf("%s\n", buf);
|
// printf("%s\n", buf);
|
||||||
watch_display_string(buf, 0);
|
watch_display_string(buf, 0);
|
||||||
|
@ -44,9 +48,6 @@ void voltage_face_setup(movement_settings_t *settings, uint8_t watch_face_index,
|
||||||
void voltage_face_activate(movement_settings_t *settings, void *context) {
|
void voltage_face_activate(movement_settings_t *settings, void *context) {
|
||||||
(void) settings;
|
(void) settings;
|
||||||
(void) context;
|
(void) context;
|
||||||
watch_enable_adc();
|
|
||||||
// if we set the reference voltage here, watch_get_vcc_voltage won't do it over and over
|
|
||||||
watch_set_analog_reference_voltage(ADC_REFERENCE_INTREF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool voltage_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
bool voltage_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||||
|
@ -73,6 +74,7 @@ bool voltage_face_loop(movement_event_t event, movement_settings_t *settings, vo
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
case EVENT_LOW_ENERGY_UPDATE:
|
||||||
|
watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
|
||||||
watch_display_string("BA SLEEP ", 0);
|
watch_display_string("BA SLEEP ", 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -85,7 +87,4 @@ bool voltage_face_loop(movement_event_t event, movement_settings_t *settings, vo
|
||||||
void voltage_face_resign(movement_settings_t *settings, void *context) {
|
void voltage_face_resign(movement_settings_t *settings, void *context) {
|
||||||
(void) settings;
|
(void) settings;
|
||||||
(void) context;
|
(void) context;
|
||||||
// make sure to restore the default in the end.
|
|
||||||
watch_set_analog_reference_voltage(ADC_REFERENCE_VCC);
|
|
||||||
watch_disable_adc();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ bool thermistor_readout_face_loop(movement_event_t event, movement_settings_t *s
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
case EVENT_LIGHT_BUTTON_DOWN:
|
||||||
movement_illuminate_led();
|
movement_illuminate_led();
|
||||||
break;
|
break;
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
case EVENT_ALARM_BUTTON_DOWN:
|
||||||
settings->bit.use_imperial_units = !settings->bit.use_imperial_units;
|
settings->bit.use_imperial_units = !settings->bit.use_imperial_units;
|
||||||
_thermistor_readout_face_update_display(settings->bit.use_imperial_units);
|
_thermistor_readout_face_update_display(settings->bit.use_imperial_units);
|
||||||
break;
|
break;
|
||||||
|
|
88
movement/watch_faces/sensor/thermistor_testing_face.c
Normal file
88
movement/watch_faces/sensor/thermistor_testing_face.c
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "thermistor_testing_face.h"
|
||||||
|
#include "thermistor_driver.h"
|
||||||
|
#include "watch.h"
|
||||||
|
|
||||||
|
// This watch face is designed for testing temperature sensor boards.
|
||||||
|
// It displays temperature readings at a relatively fast rate of 8 Hz,
|
||||||
|
// and disables low energy mode so my testing device doesn't sleep.
|
||||||
|
// You more than likely want to use thermistor_readout_face instead.
|
||||||
|
|
||||||
|
static void _thermistor_testing_face_update_display(bool in_fahrenheit) {
|
||||||
|
thermistor_driver_enable();
|
||||||
|
float temperature_c = thermistor_driver_get_temperature();
|
||||||
|
char buf[14];
|
||||||
|
if (in_fahrenheit) {
|
||||||
|
sprintf(buf, "%4.1f#F", temperature_c * 1.8 + 32.0);
|
||||||
|
} else {
|
||||||
|
sprintf(buf, "%4.1f#C", temperature_c);
|
||||||
|
}
|
||||||
|
watch_display_string(buf, 4);
|
||||||
|
thermistor_driver_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void thermistor_testing_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||||
|
(void) watch_face_index;
|
||||||
|
(void) context_ptr;
|
||||||
|
// force one setting: never enter low energy mode.
|
||||||
|
// I'm using this watch face to test the temperature sensor boards; there's no need for it.
|
||||||
|
settings->bit.le_interval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thermistor_testing_face_activate(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
(void) context;
|
||||||
|
watch_display_string("TE", 0);
|
||||||
|
movement_request_tick_frequency(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool thermistor_testing_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||||
|
(void) context;
|
||||||
|
switch (event.event_type) {
|
||||||
|
case EVENT_MODE_BUTTON_UP:
|
||||||
|
movement_move_to_next_face();
|
||||||
|
break;
|
||||||
|
case EVENT_ALARM_BUTTON_DOWN:
|
||||||
|
settings->bit.use_imperial_units = !settings->bit.use_imperial_units;
|
||||||
|
_thermistor_testing_face_update_display(settings->bit.use_imperial_units);
|
||||||
|
break;
|
||||||
|
case EVENT_ACTIVATE:
|
||||||
|
case EVENT_TICK:
|
||||||
|
_thermistor_testing_face_update_display(settings->bit.use_imperial_units);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thermistor_testing_face_resign(movement_settings_t *settings, void *context) {
|
||||||
|
(void) settings;
|
||||||
|
(void) context;
|
||||||
|
}
|
43
movement/watch_faces/sensor/thermistor_testing_face.h
Normal file
43
movement/watch_faces/sensor/thermistor_testing_face.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Joey Castillo
|
||||||
|
*
|
||||||
|
* 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 THERMISTOR_TESTING_FACE_H_
|
||||||
|
#define THERMISTOR_TESTING_FACE_H_
|
||||||
|
|
||||||
|
#include "movement.h"
|
||||||
|
|
||||||
|
void thermistor_testing_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||||
|
void thermistor_testing_face_activate(movement_settings_t *settings, void *context);
|
||||||
|
bool thermistor_testing_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||||
|
void thermistor_testing_face_resign(movement_settings_t *settings, void *context);
|
||||||
|
|
||||||
|
#define thermistor_testing_face ((const watch_face_t){ \
|
||||||
|
thermistor_testing_face_setup, \
|
||||||
|
thermistor_testing_face_activate, \
|
||||||
|
thermistor_testing_face_loop, \
|
||||||
|
thermistor_testing_face_resign, \
|
||||||
|
NULL, \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif // THERMISTOR_TESTING_FACE_H_
|
|
@ -102,8 +102,8 @@ bool set_time_face_loop(movement_event_t event, movement_settings_t *settings, v
|
||||||
sprintf(buf, "%s %2d%02d%02d", set_time_face_titles[current_page], date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
|
sprintf(buf, "%s %2d%02d%02d", set_time_face_titles[current_page], date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf, "%s %2d%02d%02d", set_time_face_titles[current_page], (date_time.unit.hour % 12) ? (date_time.unit.hour % 12) : 12, date_time.unit.minute, date_time.unit.second);
|
sprintf(buf, "%s %2d%02d%02d", set_time_face_titles[current_page], (date_time.unit.hour % 12) ? (date_time.unit.hour % 12) : 12, date_time.unit.minute, date_time.unit.second);
|
||||||
if (date_time.unit.hour > 12) watch_set_indicator(WATCH_INDICATOR_PM);
|
if (date_time.unit.hour < 12) watch_clear_indicator(WATCH_INDICATOR_PM);
|
||||||
else watch_clear_indicator(WATCH_INDICATOR_PM);
|
else watch_set_indicator(WATCH_INDICATOR_PM);
|
||||||
}
|
}
|
||||||
} else if (current_page < 6) {
|
} else if (current_page < 6) {
|
||||||
watch_clear_colon();
|
watch_clear_colon();
|
||||||
|
|
5
rules.mk
5
rules.mk
|
@ -4,6 +4,8 @@ OBJS = $(addprefix $(BUILD)/, $(notdir %/$(subst .c,.o, $(SRCS))))
|
||||||
|
|
||||||
SUBMODULES = tinyusb
|
SUBMODULES = tinyusb
|
||||||
|
|
||||||
|
COBRA = cobra -f
|
||||||
|
|
||||||
ifndef EMSCRIPTEN
|
ifndef EMSCRIPTEN
|
||||||
all: directory $(SUBMODULES) $(BUILD)/$(BIN).elf $(BUILD)/$(BIN).hex $(BUILD)/$(BIN).bin $(BUILD)/$(BIN).uf2 size
|
all: directory $(SUBMODULES) $(BUILD)/$(BIN).elf $(BUILD)/$(BIN).hex $(BUILD)/$(BIN).bin $(BUILD)/$(BIN).uf2 size
|
||||||
else
|
else
|
||||||
|
@ -54,4 +56,7 @@ clean:
|
||||||
@echo clean
|
@echo clean
|
||||||
@-rm -rf $(BUILD)
|
@-rm -rf $(BUILD)
|
||||||
|
|
||||||
|
analyze:
|
||||||
|
@$(COBRA) basic $(INCLUDES) $(DEFINES) $(SRCS)
|
||||||
|
|
||||||
-include $(wildcard $(BUILD)/*.d)
|
-include $(wildcard $(BUILD)/*.d)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -66,6 +66,13 @@ int main(void) {
|
||||||
// Watch library code. Set initial parameters for the device and enable the RTC.
|
// Watch library code. Set initial parameters for the device and enable the RTC.
|
||||||
_watch_init();
|
_watch_init();
|
||||||
|
|
||||||
|
// if date/time register is 0 (power on reset state), default year to 2022.
|
||||||
|
watch_date_time date_time = watch_rtc_get_date_time();
|
||||||
|
if (date_time.reg == 0) {
|
||||||
|
date_time.unit.year = 2;
|
||||||
|
watch_rtc_set_date_time(date_time);
|
||||||
|
}
|
||||||
|
|
||||||
// User code. Give the app a chance to enable and set up peripherals.
|
// User code. Give the app a chance to enable and set up peripherals.
|
||||||
app_setup();
|
app_setup();
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ static uint16_t _watch_get_analog_value(uint16_t channel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ADC->SWTRIG.bit.START = 1;
|
ADC->SWTRIG.bit.START = 1;
|
||||||
while (!ADC->INTFLAG.bit.RESRDY);
|
while (!ADC->INTFLAG.bit.RESRDY); // wait for "result ready" flag
|
||||||
|
|
||||||
return ADC->RESULT.reg;
|
return ADC->RESULT.reg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool le
|
||||||
|
|
||||||
// disable the RTC
|
// disable the RTC
|
||||||
RTC->MODE2.CTRLA.bit.ENABLE = 0;
|
RTC->MODE2.CTRLA.bit.ENABLE = 0;
|
||||||
while (RTC->MODE2.SYNCBUSY.bit.ENABLE);
|
while (RTC->MODE2.SYNCBUSY.bit.ENABLE); // wait for RTC to be disabled
|
||||||
|
|
||||||
// update the configuration
|
// update the configuration
|
||||||
RTC->MODE2.TAMPCTRL.reg = config;
|
RTC->MODE2.TAMPCTRL.reg = config;
|
||||||
|
@ -192,15 +192,3 @@ void watch_enter_backup_mode(void) {
|
||||||
// go into backup sleep mode (5). when we exit, the reset controller will take over.
|
// go into backup sleep mode (5). when we exit, the reset controller will take over.
|
||||||
sleep(5);
|
sleep(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// deprecated
|
|
||||||
void watch_enter_shallow_sleep(bool display_on) {
|
|
||||||
if (display_on) watch_enter_sleep_mode();
|
|
||||||
else watch_enter_deep_sleep_mode();
|
|
||||||
}
|
|
||||||
|
|
||||||
// deprecated
|
|
||||||
void watch_enter_deep_sleep(void) {
|
|
||||||
watch_register_extwake_callback(BTN_ALARM, NULL, true);
|
|
||||||
watch_enter_backup_mode();
|
|
||||||
}
|
|
||||||
|
|
|
@ -101,11 +101,3 @@ void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback,
|
||||||
|
|
||||||
ext_irq_register(pin, callback);
|
ext_irq_register(pin, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void watch_register_button_callback(const uint8_t pin, ext_irq_cb_t callback) {
|
|
||||||
watch_register_interrupt_callback(pin, callback, INTERRUPT_TRIGGER_RISING);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void watch_enable_buttons(void) {
|
|
||||||
watch_enable_external_interrupts();
|
|
||||||
}
|
|
||||||
|
|
|
@ -34,16 +34,6 @@ void watch_disable_leds(void) {
|
||||||
_watch_disable_tcc();
|
_watch_disable_tcc();
|
||||||
}
|
}
|
||||||
|
|
||||||
void watch_enable_led(bool unused) {
|
|
||||||
(void)unused;
|
|
||||||
watch_enable_leds();
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_disable_led(bool unused) {
|
|
||||||
(void)unused;
|
|
||||||
watch_disable_leds();
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_set_led_color(uint8_t red, uint8_t green) {
|
void watch_set_led_color(uint8_t red, uint8_t green) {
|
||||||
if (hri_tcc_get_CTRLA_reg(TCC0, TCC_CTRLA_ENABLE)) {
|
if (hri_tcc_get_CTRLA_reg(TCC0, TCC_CTRLA_ENABLE)) {
|
||||||
uint32_t period = hri_tcc_get_PER_reg(TCC0, TCC_PER_MASK);
|
uint32_t period = hri_tcc_get_PER_reg(TCC0, TCC_PER_MASK);
|
||||||
|
|
|
@ -35,7 +35,7 @@ void _watch_init(void) {
|
||||||
|
|
||||||
// Use switching regulator for lower power consumption.
|
// Use switching regulator for lower power consumption.
|
||||||
SUPC->VREG.bit.SEL = 1;
|
SUPC->VREG.bit.SEL = 1;
|
||||||
while(!SUPC->STATUS.bit.VREGRDY);
|
while(!SUPC->STATUS.bit.VREGRDY); // wait for voltage regulator to become ready
|
||||||
|
|
||||||
// check the battery voltage...
|
// check the battery voltage...
|
||||||
watch_enable_adc();
|
watch_enable_adc();
|
||||||
|
@ -63,7 +63,7 @@ void _watch_init(void) {
|
||||||
SUPC->BOD33.bit.LEVEL = 34; // Detect brownout at 2.6V (1.445V + level * 34mV)
|
SUPC->BOD33.bit.LEVEL = 34; // Detect brownout at 2.6V (1.445V + level * 34mV)
|
||||||
SUPC->BOD33.bit.ACTION = 0x2; // Generate an interrupt when BOD33 is triggered
|
SUPC->BOD33.bit.ACTION = 0x2; // Generate an interrupt when BOD33 is triggered
|
||||||
SUPC->BOD33.bit.HYST = 0; // Disable hysteresis
|
SUPC->BOD33.bit.HYST = 0; // Disable hysteresis
|
||||||
while(!SUPC->STATUS.bit.B33SRDY);
|
while(!SUPC->STATUS.bit.B33SRDY); // wait for BOD33 to sync
|
||||||
|
|
||||||
// Enable interrupt on BOD33 detect
|
// Enable interrupt on BOD33 detect
|
||||||
SUPC->INTENSET.bit.BOD33DET = 1;
|
SUPC->INTENSET.bit.BOD33DET = 1;
|
||||||
|
@ -198,7 +198,7 @@ void _watch_enable_usb(void) {
|
||||||
|
|
||||||
// assign DFLL to GCLK1
|
// assign DFLL to GCLK1
|
||||||
GCLK->GENCTRL[1].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL48M) | GCLK_GENCTRL_DIV(1) | GCLK_GENCTRL_GENEN;// | GCLK_GENCTRL_OE;
|
GCLK->GENCTRL[1].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL48M) | GCLK_GENCTRL_DIV(1) | GCLK_GENCTRL_GENEN;// | GCLK_GENCTRL_OE;
|
||||||
while (GCLK->SYNCBUSY.bit.GENCTRL1);
|
while (GCLK->SYNCBUSY.bit.GENCTRL1); // wait for generator control 1 to sync
|
||||||
|
|
||||||
// assign GCLK1 to USB
|
// assign GCLK1 to USB
|
||||||
hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN);
|
hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN);
|
||||||
|
@ -260,15 +260,6 @@ int _read(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alternate function that outputs to the debug UART. useful for debugging USB issues.
|
|
||||||
// int _write(int file, char *ptr, int len) {
|
|
||||||
// (void)file;
|
|
||||||
// int pos = 0;
|
|
||||||
// while(pos < len) watch_debug_putc(ptr[pos++]);
|
|
||||||
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
void USB_Handler(void) {
|
void USB_Handler(void) {
|
||||||
tud_int_handler(0);
|
tud_int_handler(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,40 +160,3 @@ void RTC_Handler(void) {
|
||||||
RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0;
|
RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////
|
|
||||||
// Deprecated functions
|
|
||||||
|
|
||||||
void watch_set_date_time(struct calendar_date_time date_time) {
|
|
||||||
RTC_MODE2_CLOCK_Type val;
|
|
||||||
|
|
||||||
val.bit.SECOND = date_time.time.sec;
|
|
||||||
val.bit.MINUTE = date_time.time.min;
|
|
||||||
val.bit.HOUR = date_time.time.hour;
|
|
||||||
val.bit.DAY = date_time.date.day;
|
|
||||||
val.bit.MONTH = date_time.date.month;
|
|
||||||
val.bit.YEAR = (uint8_t)(date_time.date.year - WATCH_RTC_REFERENCE_YEAR);
|
|
||||||
|
|
||||||
RTC->MODE2.CLOCK.reg = val.reg;
|
|
||||||
|
|
||||||
_sync_rtc();
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_get_date_time(struct calendar_date_time *date_time) {
|
|
||||||
_sync_rtc();
|
|
||||||
RTC_MODE2_CLOCK_Type val = RTC->MODE2.CLOCK;
|
|
||||||
|
|
||||||
date_time->time.sec = val.bit.SECOND;
|
|
||||||
date_time->time.min = val.bit.MINUTE;
|
|
||||||
date_time->time.hour = val.bit.HOUR;
|
|
||||||
date_time->date.day = val.bit.DAY;
|
|
||||||
date_time->date.month = val.bit.MONTH;
|
|
||||||
date_time->date.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_register_tick_callback(ext_irq_cb_t callback) {
|
|
||||||
tick_callbacks[7] = callback;
|
|
||||||
NVIC_ClearPendingIRQ(RTC_IRQn);
|
|
||||||
NVIC_EnableIRQ(RTC_IRQn);
|
|
||||||
RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_PER7;
|
|
||||||
}
|
|
||||||
|
|
|
@ -116,70 +116,3 @@ char watch_uart_getc(void) {
|
||||||
io_read(uart_io, &retval, 1);
|
io_read(uart_io, &retval, 1);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin deprecated functions
|
|
||||||
|
|
||||||
/*
|
|
||||||
* UART methods are Copyright (c) 2014-2017, Alex Taradov <alex@taradov.com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "peripheral_clk_config.h"
|
|
||||||
|
|
||||||
void watch_enable_debug_uart(uint32_t baud) {
|
|
||||||
uint64_t br = (uint64_t)65536 * ((CONF_CPU_FREQUENCY * 4) - 16 * baud) / (CONF_CPU_FREQUENCY * 4);
|
|
||||||
|
|
||||||
gpio_set_pin_direction(A2, GPIO_DIRECTION_OUT);
|
|
||||||
gpio_set_pin_function(A2, PINMUX_PB02C_SERCOM3_PAD0);
|
|
||||||
|
|
||||||
MCLK->APBCMASK.reg |= MCLK_APBCMASK_SERCOM3;
|
|
||||||
|
|
||||||
GCLK->PCHCTRL[SERCOM3_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN(0) | GCLK_PCHCTRL_CHEN;
|
|
||||||
while (0 == (GCLK->PCHCTRL[SERCOM3_GCLK_ID_CORE].reg & GCLK_PCHCTRL_CHEN));
|
|
||||||
|
|
||||||
SERCOM3->USART.CTRLA.reg =
|
|
||||||
SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE(1/*USART_INT_CLK*/) |
|
|
||||||
SERCOM_USART_CTRLA_RXPO(1/*PAD1*/) | SERCOM_USART_CTRLA_TXPO(0/*PAD0*/);
|
|
||||||
|
|
||||||
SERCOM3->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN |
|
|
||||||
SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/);
|
|
||||||
|
|
||||||
SERCOM3->USART.BAUD.reg = (uint16_t)br;
|
|
||||||
|
|
||||||
SERCOM3->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_debug_putc(char c) {
|
|
||||||
while (!(SERCOM3->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE));
|
|
||||||
SERCOM3->USART.DATA.reg = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
void watch_debug_puts(char *s) {
|
|
||||||
while (*s) watch_debug_putc(*s++);
|
|
||||||
}
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
|
@ -1,143 +0,0 @@
|
||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Joey Castillo
|
|
||||||
*
|
|
||||||
* 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 "lis2dh.h"
|
|
||||||
#include "watch.h"
|
|
||||||
|
|
||||||
bool lis2dh_begin(void) {
|
|
||||||
if (lis2dh_get_device_id() != LIS2DH_WHO_AM_I_VAL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Enable all axes, start at lowest possible data rate
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL1, LIS2DH_CTRL1_VAL_XEN |
|
|
||||||
LIS2DH_CTRL1_VAL_YEN |
|
|
||||||
LIS2DH_CTRL1_VAL_ZEN |
|
|
||||||
LIS2DH_CTRL1_VAL_ODR_1HZ);
|
|
||||||
// Set range to ±2G and enable block data update (output registers not updated until MSB and LSB have been read)
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL4, LIS2DH_CTRL4_VAL_BDU | LIS2DH_RANGE_2_G);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t lis2dh_get_device_id(void) {
|
|
||||||
return watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_WHO_AM_I);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lis2dh_have_new_data(void) {
|
|
||||||
uint8_t retval = watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_STATUS);
|
|
||||||
return !!retval; // return true if any bit is set
|
|
||||||
}
|
|
||||||
|
|
||||||
lis2dh_reading lis2dh_get_raw_reading(void) {
|
|
||||||
uint8_t buffer[6];
|
|
||||||
uint8_t reg = LIS2DH_REG_OUT_X_L | 0x80; // set high bit for consecutive reads
|
|
||||||
lis2dh_reading retval;
|
|
||||||
|
|
||||||
watch_i2c_send(LIS2DH_ADDRESS, ®, 1);
|
|
||||||
watch_i2c_receive(LIS2DH_ADDRESS, (uint8_t *)&buffer, 6);
|
|
||||||
|
|
||||||
retval.x = buffer[0];
|
|
||||||
retval.x |= ((uint16_t)buffer[1]) << 8;
|
|
||||||
retval.y = buffer[2];
|
|
||||||
retval.y |= ((uint16_t)buffer[3]) << 8;
|
|
||||||
retval.z = buffer[4];
|
|
||||||
retval.z |= ((uint16_t)buffer[5]) << 8;
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
lis2dh_acceleration_measurement lis2dh_get_acceleration_measurement(lis2dh_reading *out_reading) {
|
|
||||||
lis2dh_reading reading = lis2dh_get_raw_reading();
|
|
||||||
uint8_t range = lis2dh_get_range();
|
|
||||||
if (out_reading != NULL) *out_reading = reading;
|
|
||||||
|
|
||||||
// this bit is cribbed from Adafruit's LIS3DH driver; from their notes, the magic number below
|
|
||||||
// converts from 16-bit lsb to 10-bit and divides by 1k to convert from milli-gs.
|
|
||||||
// final value is raw_lsb => 10-bit lsb -> milli-gs -> gs
|
|
||||||
uint8_t lsb_value = 1;
|
|
||||||
if (range == LIS2DH_RANGE_2_G) lsb_value = 4;
|
|
||||||
if (range == LIS2DH_RANGE_4_G) lsb_value = 8;
|
|
||||||
if (range == LIS2DH_RANGE_8_G) lsb_value = 16;
|
|
||||||
if (range == LIS2DH_RANGE_16_G) lsb_value = 48;
|
|
||||||
|
|
||||||
lis2dh_acceleration_measurement retval;
|
|
||||||
|
|
||||||
retval.x = lsb_value * ((float)reading.x / 64000.0);
|
|
||||||
retval.y = lsb_value * ((float)reading.y / 64000.0);
|
|
||||||
retval.z = lsb_value * ((float)reading.z / 64000.0);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lis2dh_set_range(lis2dh_range_t range) {
|
|
||||||
uint8_t val = watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL4) & 0xCF;
|
|
||||||
uint8_t bits = range << 4;
|
|
||||||
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL4, val | bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
lis2dh_range_t lis2dh_get_range(void) {
|
|
||||||
uint8_t retval = watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL4) & 0x30;
|
|
||||||
retval >>= 4;
|
|
||||||
return (lis2dh_range_t)retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void lis2dh_set_data_rate(lis2dh_data_rate_t dataRate) {
|
|
||||||
uint8_t val = watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL1) & 0x0F;
|
|
||||||
uint8_t bits = dataRate << 4;
|
|
||||||
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL1, val | bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
lis2dh_data_rate_t lis2dh_get_data_rate(void) {
|
|
||||||
return watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL1) >> 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lis2dh_configure_aoi_int1(lis2dh_interrupt_configuration configuration, uint8_t threshold, uint8_t duration, bool latch) {
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL3, LIS2DH_CTRL3_VAL_I1_AOI1);
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_INT1_CFG, configuration);
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_INT1_THS, threshold);
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_INT1_DUR, duration);
|
|
||||||
uint8_t val = watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL5) & 0xF7;
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL5, val | latch ? LIS2DH_CTRL5_VAL_LIR_INT1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
lis2dh_interrupt_state lis2dh_get_int1_state(void) {
|
|
||||||
return (lis2dh_interrupt_state) watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_INT1_SRC);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lis2dh_configure_aoi_int2(lis2dh_interrupt_configuration configuration, uint8_t threshold, uint8_t duration, bool latch) {
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL6, LIS2DH_CTRL6_VAL_I2_INT2);
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_INT2_CFG, configuration);
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_INT2_THS, threshold);
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_INT2_DUR, duration);
|
|
||||||
uint8_t val = watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL5) & 0xFD;
|
|
||||||
watch_i2c_write8(LIS2DH_ADDRESS, LIS2DH_REG_CTRL5, val | latch ? LIS2DH_CTRL5_VAL_LIR_INT2 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
lis2dh_interrupt_state lis2dh_get_int2_state(void) {
|
|
||||||
return (lis2dh_interrupt_state) watch_i2c_read8(LIS2DH_ADDRESS, LIS2DH_REG_INT2_SRC);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,222 +0,0 @@
|
||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Joey Castillo
|
|
||||||
*
|
|
||||||
* 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 LIS2DH_H
|
|
||||||
#define LIS2DH_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int16_t x;
|
|
||||||
int16_t y;
|
|
||||||
int16_t z;
|
|
||||||
} lis2dh_reading;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float x;
|
|
||||||
float y;
|
|
||||||
float z;
|
|
||||||
} lis2dh_acceleration_measurement;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
LIS2DH_RANGE_16_G = 0b11, // +/- 16g
|
|
||||||
LIS2DH_RANGE_8_G = 0b10, // +/- 8g
|
|
||||||
LIS2DH_RANGE_4_G = 0b01, // +/- 4g
|
|
||||||
LIS2DH_RANGE_2_G = 0b00 // +/- 2g (default value)
|
|
||||||
} lis2dh_range_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
LIS2DH_DATA_RATE_POWERDOWN = 0,
|
|
||||||
LIS2DH_DATA_RATE_1_HZ = 0b0001,
|
|
||||||
LIS2DH_DATA_RATE_10_HZ = 0b0010,
|
|
||||||
LIS2DH_DATA_RATE_25_HZ = 0b0011,
|
|
||||||
LIS2DH_DATA_RATE_50_HZ = 0b0100,
|
|
||||||
LIS2DH_DATA_RATE_100_HZ = 0b0101,
|
|
||||||
LIS2DH_DATA_RATE_200_HZ = 0b0110,
|
|
||||||
LIS2DH_DATA_RATE_400_HZ = 0b0111,
|
|
||||||
LIS2DH_DATA_RATE_LP1620HZ = 0b1000,
|
|
||||||
LIS2DH_DATA_RATE_LP5376HZ = 0b1001,
|
|
||||||
|
|
||||||
} lis2dh_data_rate_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_OR = 0b00000000,
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_AND = 0b10000000,
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_6D_MOVEMENT = 0b01000000,
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_6D_POSITION = 0b11000000, // in 6D mode, these have an alternate meaning:
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_Z_HIGH_ENABLE = 0b00100000, // Z up enable
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_Z_LOW_ENABLE = 0b00010000, // Z down enable
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_Y_HIGH_ENABLE = 0b00001000, // Y up enable
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_Y_LOW_ENABLE = 0b00000100, // Y down enable
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_X_HIGH_ENABLE = 0b00000010, // X up enable
|
|
||||||
LIS2DH_INTERRUPT_CONFIGURATION_X_LOW_ENABLE = 0b00000001, // X down enable
|
|
||||||
} lis2dh_interrupt_configuration;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
LIS2DH_INTERRUPT_STATE_ACTIVE = 0b01000000,
|
|
||||||
LIS2DH_INTERRUPT_STATE_Z_HIGH = 0b00100000, // Z up
|
|
||||||
LIS2DH_INTERRUPT_STATE_Z_LOW = 0b00010000, // Z down
|
|
||||||
LIS2DH_INTERRUPT_STATE_Y_HIGH = 0b00001000, // Y up
|
|
||||||
LIS2DH_INTERRUPT_STATE_Y_LOW = 0b00000100, // Y down
|
|
||||||
LIS2DH_INTERRUPT_STATE_X_HIGH = 0b00000010, // X up
|
|
||||||
LIS2DH_INTERRUPT_STATE_X_LOW = 0b00000001, // X down
|
|
||||||
} lis2dh_interrupt_state;
|
|
||||||
|
|
||||||
bool lis2dh_begin(void);
|
|
||||||
|
|
||||||
uint8_t lis2dh_get_device_id(void);
|
|
||||||
|
|
||||||
bool lis2dh_have_new_data(void);
|
|
||||||
|
|
||||||
lis2dh_reading lis2dh_get_raw_reading(void);
|
|
||||||
|
|
||||||
lis2dh_acceleration_measurement lis2dh_get_acceleration_measurement(lis2dh_reading *out_reading);
|
|
||||||
|
|
||||||
void lis2dh_set_range(lis2dh_range_t range);
|
|
||||||
|
|
||||||
lis2dh_range_t lis2dh_get_range(void);
|
|
||||||
|
|
||||||
void lis2dh_set_data_rate(lis2dh_data_rate_t dataRate);
|
|
||||||
|
|
||||||
lis2dh_data_rate_t lis2dh_get_data_rate(void);
|
|
||||||
|
|
||||||
void lis2dh_configure_aoi_int1(lis2dh_interrupt_configuration configuration, uint8_t threshold, uint8_t duration, bool latch);
|
|
||||||
|
|
||||||
lis2dh_interrupt_state lis2dh_get_int1_state(void);
|
|
||||||
|
|
||||||
void lis2dh_configure_aoi_int2(lis2dh_interrupt_configuration configuration, uint8_t threshold, uint8_t duration, bool latch);
|
|
||||||
|
|
||||||
lis2dh_interrupt_state lis2dh_get_int2_state(void);
|
|
||||||
|
|
||||||
// Assumes SA0 is high; if low, its 0x18
|
|
||||||
#define LIS2DH_ADDRESS (0x19)
|
|
||||||
|
|
||||||
#define LIS2DH_REG_STATUS_AUX 0x07 ///< Auxiliary status register
|
|
||||||
#define LIS2DH_REG_STATUS_AUX_TDA (1 << 2) ///< Temperature data available
|
|
||||||
#define LIS2DH_REG_STATUS_AUX_TOR (1 << 6) ///< Temperature data overrun
|
|
||||||
|
|
||||||
#define LIS2DH_REG_OUT_TEMP_L 0x0C ///< Temperature data low bit
|
|
||||||
#define LIS2DH_REG_OUT_TEMP_H 0x0D ///< Temperature data high bit
|
|
||||||
|
|
||||||
#define LIS2DH_REG_INT_COUNTER 0x0E
|
|
||||||
|
|
||||||
#define LIS2DH_REG_WHO_AM_I 0x0F ///< Device identification, will read 0x33
|
|
||||||
#define LIS2DH_WHO_AM_I_VAL 0x33 ///< Expected value of the WHO_AM_I register
|
|
||||||
|
|
||||||
#define LIS2DH_REG_TEMP_CFG 0x1F ///< Temperature configuration; 0 to disable, 0xC0 to enable.
|
|
||||||
#define LIS2DH_TEMP_CFG_VAL_ENABLE 0xC0 ///< Value for LIS2DH_REG_TEMP_CFG that enables temperature sensing.
|
|
||||||
#define LIS2DH_TEMP_CFG_VAL_DISABLE 0x00 ///< Value for LIS2DH_REG_TEMP_CFG that disables temperature sensing.
|
|
||||||
|
|
||||||
#define LIS2DH_REG_CTRL1 0x20 ///< CTRL_REG1 in the data sheet.
|
|
||||||
#define LIS2DH_CTRL1_VAL_XEN 0b00000001 ///< Enable X-axis
|
|
||||||
#define LIS2DH_CTRL1_VAL_YEN 0b00000010 ///< Enable Y-axis
|
|
||||||
#define LIS2DH_CTRL1_VAL_ZEN 0b00000100 ///< Enable Z-axis
|
|
||||||
#define LIS2DH_CTRL1_VAL_LPEN 0b00001000 ///< Enable low power mode
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_POWERDOWN 0 ///< Power down
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_1HZ (LIS2DH_DATA_RATE_1_HZ << 4)
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_10HZ (LIS2DH_DATA_RATE_10_HZ << 4)
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_25HZ (LIS2DH_DATA_RATE_25_HZ << 4)
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_50HZ (LIS2DH_DATA_RATE_50_HZ << 4)
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_100HZ (LIS2DH_DATA_RATE_100_HZ << 4)
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_200HZ (LIS2DH_DATA_RATE_200_HZ << 4)
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_400HZ (LIS2DH_DATA_RATE_400_HZ << 4)
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_LP1620HZ (LIS2DH_DATA_RATE_LP1620HZ << 4)
|
|
||||||
#define LIS2DH_CTRL1_VAL_ODR_LP5376HZ (LIS2DH_DATA_RATE_LP5376HZ << 4)
|
|
||||||
|
|
||||||
#define LIS2DH_REG_CTRL2 0x21
|
|
||||||
|
|
||||||
#define LIS2DH_REG_CTRL3 0x22
|
|
||||||
#define LIS2DH_CTRL3_VAL_I1_CLICK 0b10000000
|
|
||||||
#define LIS2DH_CTRL3_VAL_I1_AOI1 0b01000000
|
|
||||||
#define LIS2DH_CTRL3_VAL_I1_AOI2 0b00100000
|
|
||||||
#define LIS2DH_CTRL3_VAL_I1_DRDY1 0b00010000
|
|
||||||
#define LIS2DH_CTRL3_VAL_I1_DRDY2 0b00001000
|
|
||||||
#define LIS2DH_CTRL3_VAL_I1_WTM 0b00000100
|
|
||||||
#define LIS2DH_CTRL3_VAL_I1_OVERRUN 0b00000010
|
|
||||||
|
|
||||||
#define LIS2DH_REG_CTRL4 0x23
|
|
||||||
#define LIS2DH_CTRL4_VAL_BDU 0b10000000
|
|
||||||
#define LIS2DH_CTRL4_VAL_BLE 0b01000000
|
|
||||||
#define LIS2DH_CTRL4_VAL_RANGE_2G (LIS2DH_RANGE_2_G << 4)
|
|
||||||
#define LIS2DH_CTRL4_VAL_RANGE_4G (LIS2DH_RANGE_4_G << 4)
|
|
||||||
#define LIS2DH_CTRL4_VAL_RANGE_8G (LIS2DH_RANGE_8_G << 4)
|
|
||||||
#define LIS2DH_CTRL4_VAL_RANGE_16G (LIS2DH_RANGE_16_G << 4)
|
|
||||||
#define LIS2DH_CTRL4_VAL_HR 0b00001000
|
|
||||||
#define LIS2DH_CTRL4_VAL_ST0 0b00000000
|
|
||||||
#define LIS2DH_CTRL4_VAL_ST1 0b00000000
|
|
||||||
|
|
||||||
#define LIS2DH_REG_CTRL5 0x24
|
|
||||||
#define LIS2DH_CTRL5_VAL_BOOT 0b10000000
|
|
||||||
#define LIS2DH_CTRL5_VAL_FIFO_EN 0b01000000
|
|
||||||
#define LIS2DH_CTRL5_VAL_LIR_INT1 0b00001000
|
|
||||||
#define LIS2DH_CTRL5_VAL_D4D_INT1 0b00000100
|
|
||||||
#define LIS2DH_CTRL5_VAL_LIR_INT2 0b00000010
|
|
||||||
#define LIS2DH_CTRL5_VAL_D4D_INT2 0b00000001
|
|
||||||
|
|
||||||
#define LIS2DH_REG_CTRL6 0x25
|
|
||||||
#define LIS2DH_CTRL6_VAL_I2_CLICK 0b10000000
|
|
||||||
#define LIS2DH_CTRL6_VAL_I2_INT1 0b01000000
|
|
||||||
#define LIS2DH_CTRL6_VAL_I2_INT2 0b00100000
|
|
||||||
#define LIS2DH_CTRL6_VAL_BOOT_I2 0b00010000
|
|
||||||
#define LIS2DH_CTRL6_VAL_P2_ACT 0b00001000
|
|
||||||
#define LIS2DH_CTRL6_VAL_H_L_ACTIVE 0b00000000
|
|
||||||
|
|
||||||
#define LIS2DH_REG_REFERENCE 0x26
|
|
||||||
|
|
||||||
#define LIS2DH_REG_STATUS 0x27
|
|
||||||
#define LIS2DH_STATUS_VAL_ZYXOR 0b10000000
|
|
||||||
#define LIS2DH_STATUS_VAL_ZOR 0b01000000
|
|
||||||
#define LIS2DH_STATUS_VAL_YOR 0b00100000
|
|
||||||
#define LIS2DH_STATUS_VAL_XOR 0b00010000
|
|
||||||
#define LIS2DH_STATUS_VAL_ZYXDA 0b00001000
|
|
||||||
#define LIS2DH_STATUS_VAL_ZDA 0b00000100
|
|
||||||
#define LIS2DH_STATUS_VAL_YDA 0b00000010
|
|
||||||
#define LIS2DH_STATUS_VAL_XDA 0b00000001
|
|
||||||
|
|
||||||
#define LIS2DH_REG_OUT_X_L 0x28
|
|
||||||
#define LIS2DH_REG_OUT_X_H 0x29
|
|
||||||
#define LIS2DH_REG_OUT_Y_L 0x2A
|
|
||||||
#define LIS2DH_REG_OUT_Y_H 0x2B
|
|
||||||
#define LIS2DH_REG_OUT_Z_L 0x2C
|
|
||||||
#define LIS2DH_REG_OUT_Z_H 0x2D
|
|
||||||
|
|
||||||
#define LIS2DH_REG_FIFO_CTRL 0x2E
|
|
||||||
#define LIS2DH_REG_FIFO_SRC 0x2F
|
|
||||||
#define LIS2DH_REG_INT1_CFG 0x30
|
|
||||||
#define LIS2DH_REG_INT1_SRC 0x31
|
|
||||||
#define LIS2DH_REG_INT1_THS 0x32
|
|
||||||
#define LIS2DH_REG_INT1_DUR 0x33
|
|
||||||
#define LIS2DH_REG_INT2_CFG 0x34
|
|
||||||
#define LIS2DH_REG_INT2_SRC 0x35
|
|
||||||
#define LIS2DH_REG_INT2_THS 0x36
|
|
||||||
#define LIS2DH_REG_INT2_DUR 0x37
|
|
||||||
#define LIS2DH_REG_CLICK_CFG 0x38
|
|
||||||
#define LIS2DH_REG_CLICK_SRC 0x39
|
|
||||||
#define LIS2DH_REG_CLICK_THS 0x3A
|
|
||||||
#define LIS2DH_REG_TIME_LIMIT 0x3B
|
|
||||||
#define LIS2DH_REG_TIME_LATENCY 0x3C
|
|
||||||
#define LIS2DH_REG_TIME_WINDOW 0x3D
|
|
||||||
|
|
||||||
#endif // LIS2DH_H
|
|
|
@ -207,3 +207,32 @@ void lis2dw_clear_fifo(void) {
|
||||||
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_FIFO_CTRL, LIS2DW_FIFO_CTRL_MODE_OFF);
|
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_FIFO_CTRL, LIS2DW_FIFO_CTRL_MODE_OFF);
|
||||||
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_FIFO_CTRL, LIS2DW_FIFO_CTRL_MODE_COLLECT_AND_STOP | LIS2DW_FIFO_CTRL_FTH);
|
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_FIFO_CTRL, LIS2DW_FIFO_CTRL_MODE_COLLECT_AND_STOP | LIS2DW_FIFO_CTRL_FTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lis2dw_configure_wakeup_int1(uint8_t threshold, bool latch, bool active_state) {
|
||||||
|
uint8_t configuration;
|
||||||
|
|
||||||
|
// enable wakeup interrupt on INT1 pin
|
||||||
|
configuration = watch_i2c_read8(LIS2DW_ADDRESS, LIS2DW_REG_CTRL4_INT1);
|
||||||
|
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_CTRL4_INT1, configuration | LIS2DW_CTRL4_INT1_WU);
|
||||||
|
|
||||||
|
// set threshold
|
||||||
|
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_WAKE_UP_THS, threshold | LIS2DW_WAKE_UP_THS_VAL_SLEEP_ON);
|
||||||
|
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_INT1_DUR, 0b01111111);
|
||||||
|
|
||||||
|
configuration = watch_i2c_read8(LIS2DW_ADDRESS, LIS2DW_REG_CTRL3) & ~(LIS2DW_CTRL3_VAL_LIR);
|
||||||
|
if (!active_state) configuration |= LIS2DW_CTRL3_VAL_H_L_ACTIVE;
|
||||||
|
if (latch) configuration |= LIS2DW_CTRL3_VAL_LIR;
|
||||||
|
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_CTRL3, configuration);
|
||||||
|
|
||||||
|
// enable interrupts
|
||||||
|
configuration = watch_i2c_read8(LIS2DW_ADDRESS, LIS2DW_REG_CTRL7);
|
||||||
|
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_CTRL7, configuration | LIS2DW_CTRL7_VAL_INTERRUPTS_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
lis2dw_wakeup_source lis2dw_get_wakeup_source() {
|
||||||
|
return (lis2dw_wakeup_source) watch_i2c_read8(LIS2DW_ADDRESS, LIS2DW_REG_WAKE_UP_SRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
lis2dw_interrupt_source lis2dw_get_interrupt_source(void) {
|
||||||
|
return (lis2dw_interrupt_source) watch_i2c_read8(LIS2DW_ADDRESS, LIS2DW_REG_ALL_INT_SRC);
|
||||||
|
}
|
||||||
|
|
|
@ -99,6 +99,24 @@ typedef enum {
|
||||||
LIS2DW_RANGE_2_G = 0b00 // +/- 2g (default value)
|
LIS2DW_RANGE_2_G = 0b00 // +/- 2g (default value)
|
||||||
} lis2dw_range_t;
|
} lis2dw_range_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LIS2DW_INTERRUPT_SRC_SLEEP_CHANGE = 0b00100000,
|
||||||
|
LIS2DW_INTERRUPT_SRC_6D = 0b00010000,
|
||||||
|
LIS2DW_INTERRUPT_SRC_DOUBLE_TAP = 0b00001000,
|
||||||
|
LIS2DW_INTERRUPT_SRC_SINGLE_TAP = 0b00000100,
|
||||||
|
LIS2DW_INTERRUPT_SRC_WU = 0b00000010,
|
||||||
|
LIS2DW_INTERRUPT_SRC_FF = 0b00000001
|
||||||
|
} lis2dw_interrupt_source;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LIS2DW_WAKEUP_SRC_FREEFALL = 0b00100000,
|
||||||
|
LIS2DW_WAKEUP_SRC_SLEEP_STATE = 0b00010000,
|
||||||
|
LIS2DW_WAKEUP_SRC_WAKEUP = 0b00001000,
|
||||||
|
LIS2DW_WAKEUP_SRC_WAKEUP_X = 0b00000100,
|
||||||
|
LIS2DW_WAKEUP_SRC_WAKEUP_Y = 0b00000010,
|
||||||
|
LIS2DW_WAKEUP_SRC_WAKEUP_Z = 0b00000001
|
||||||
|
} lis2dw_wakeup_source;
|
||||||
|
|
||||||
// Assumes SA0 is high; if low, its 0x18
|
// Assumes SA0 is high; if low, its 0x18
|
||||||
#define LIS2DW_ADDRESS (0x19)
|
#define LIS2DW_ADDRESS (0x19)
|
||||||
|
|
||||||
|
@ -135,15 +153,15 @@ typedef enum {
|
||||||
#define LIS2DW_CTRL2_VAL_IF_ADD_INC 0b00000100
|
#define LIS2DW_CTRL2_VAL_IF_ADD_INC 0b00000100
|
||||||
|
|
||||||
#define LIS2DW_REG_CTRL3 0x22
|
#define LIS2DW_REG_CTRL3 0x22
|
||||||
#define LIS2DW_CTRL4_VAL_SELF_TEST_POS 0b10000000
|
#define LIS2DW_CTRL3_VAL_SELF_TEST_POS 0b10000000
|
||||||
#define LIS2DW_CTRL4_VAL_SELF_TEST_NEG 0b01000000
|
#define LIS2DW_CTRL3_VAL_SELF_TEST_NEG 0b01000000
|
||||||
#define LIS2DW_CTRL3_VAL_PP_OD 0b00100000
|
#define LIS2DW_CTRL3_VAL_PP_OD 0b00100000
|
||||||
#define LIS2DW_CTRL3_VAL_LIR 0b00010000
|
#define LIS2DW_CTRL3_VAL_LIR 0b00010000
|
||||||
#define LIS2DW_CTRL3_VAL_H_L_ACTIVE 0b00001000
|
#define LIS2DW_CTRL3_VAL_H_L_ACTIVE 0b00001000
|
||||||
#define LIS2DW_CTRL3_VAL_SLP_MODE_SEL 0b00000010
|
#define LIS2DW_CTRL3_VAL_SLP_MODE_SEL 0b00000010
|
||||||
#define LIS2DW_CTRL3_VAL_SLP_MODE_1 0b00000001
|
#define LIS2DW_CTRL3_VAL_SLP_MODE_1 0b00000001
|
||||||
|
|
||||||
#define LIS2DW_REG_CTRL4 0x23
|
#define LIS2DW_REG_CTRL4_INT1 0x23
|
||||||
#define LIS2DW_CTRL4_INT1_6D 0b10000000
|
#define LIS2DW_CTRL4_INT1_6D 0b10000000
|
||||||
#define LIS2DW_CTRL4_INT1_SINGLE_TAP 0b01000000
|
#define LIS2DW_CTRL4_INT1_SINGLE_TAP 0b01000000
|
||||||
#define LIS2DW_CTRL4_INT1_WU 0b00100000
|
#define LIS2DW_CTRL4_INT1_WU 0b00100000
|
||||||
|
@ -153,7 +171,7 @@ typedef enum {
|
||||||
#define LIS2DW_CTRL4_INT1_FTH 0b00000010
|
#define LIS2DW_CTRL4_INT1_FTH 0b00000010
|
||||||
#define LIS2DW_CTRL4_INT1_DRDY 0b00000001
|
#define LIS2DW_CTRL4_INT1_DRDY 0b00000001
|
||||||
|
|
||||||
#define LIS2DW_REG_CTRL5 0x24
|
#define LIS2DW_REG_CTRL5_INT2 0x24
|
||||||
#define LIS2DW_CTRL5_INT2_SLEEP_STATE 0b10000000
|
#define LIS2DW_CTRL5_INT2_SLEEP_STATE 0b10000000
|
||||||
#define LIS2DW_CTRL5_INT2_SLEEP_CHG 0b01000000
|
#define LIS2DW_CTRL5_INT2_SLEEP_CHG 0b01000000
|
||||||
#define LIS2DW_CTRL5_INT2_BOOT 0b00100000
|
#define LIS2DW_CTRL5_INT2_BOOT 0b00100000
|
||||||
|
@ -212,7 +230,11 @@ typedef enum {
|
||||||
#define LIS2DW_REG_TAP_THS_Y 0x31
|
#define LIS2DW_REG_TAP_THS_Y 0x31
|
||||||
#define LIS2DW_REG_TAP_THS_Z 0x32
|
#define LIS2DW_REG_TAP_THS_Z 0x32
|
||||||
#define LIS2DW_REG_INT1_DUR 0x33
|
#define LIS2DW_REG_INT1_DUR 0x33
|
||||||
|
|
||||||
#define LIS2DW_REG_WAKE_UP_THS 0x34
|
#define LIS2DW_REG_WAKE_UP_THS 0x34
|
||||||
|
#define LIS2DW_WAKE_UP_THS_VAL_TAP_EVENT_ENABLED 0b10000000
|
||||||
|
#define LIS2DW_WAKE_UP_THS_VAL_SLEEP_ON 0b01000000
|
||||||
|
|
||||||
#define LIS2DW_REG_WAKE_UP_DUR 0x35
|
#define LIS2DW_REG_WAKE_UP_DUR 0x35
|
||||||
#define LIS2DW_REG_FREE_FALL 0x36
|
#define LIS2DW_REG_FREE_FALL 0x36
|
||||||
#define LIS2DW_REG_STATUS_DUP 0x37
|
#define LIS2DW_REG_STATUS_DUP 0x37
|
||||||
|
@ -313,4 +335,10 @@ bool lis2dw_read_fifo(lis2dw_fifo_t *fifo_data);
|
||||||
|
|
||||||
void lis2dw_clear_fifo(void);
|
void lis2dw_clear_fifo(void);
|
||||||
|
|
||||||
|
void lis2dw_configure_wakeup_int1(uint8_t threshold, bool latch, bool active_state);
|
||||||
|
|
||||||
|
lis2dw_interrupt_source lis2dw_get_interrupt_source(void);
|
||||||
|
|
||||||
|
lis2dw_wakeup_source lis2dw_get_wakeup_source(void);
|
||||||
|
|
||||||
#endif // LIS2DW_H
|
#endif // LIS2DW_H
|
||||||
|
|
|
@ -151,10 +151,5 @@ void watch_enter_deep_sleep_mode(void);
|
||||||
*/
|
*/
|
||||||
void watch_enter_backup_mode(void);
|
void watch_enter_backup_mode(void);
|
||||||
|
|
||||||
__attribute__((deprecated("Use watch_enter_sleep_mode or watch_enter_deep_sleep_mode instead")))
|
|
||||||
void watch_enter_shallow_sleep(bool display_on);
|
|
||||||
|
|
||||||
__attribute__((deprecated("Use watch_enter_backup_mode instead")))
|
|
||||||
void watch_enter_deep_sleep(void);
|
|
||||||
/// @}
|
/// @}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -76,10 +76,5 @@ void watch_disable_external_interrupts(void);
|
||||||
*/
|
*/
|
||||||
void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, watch_interrupt_trigger trigger);
|
void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, watch_interrupt_trigger trigger);
|
||||||
|
|
||||||
__attribute__((deprecated("Use watch_register_interrupt_callback or watch_register_extwake_callback instead")))
|
|
||||||
void watch_register_button_callback(const uint8_t pin, ext_irq_cb_t callback);
|
|
||||||
|
|
||||||
__attribute__((deprecated("Use watch_enable_external_interrupts instead")))
|
|
||||||
void watch_enable_buttons(void);
|
|
||||||
/// @}
|
/// @}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -84,10 +84,5 @@ void watch_set_led_yellow(void);
|
||||||
/** @brief Turns both the red and the green LEDs off. */
|
/** @brief Turns both the red and the green LEDs off. */
|
||||||
void watch_set_led_off(void);
|
void watch_set_led_off(void);
|
||||||
|
|
||||||
__attribute__((deprecated("Use watch_enable_leds instead")))
|
|
||||||
void watch_enable_led(bool unused);
|
|
||||||
|
|
||||||
__attribute__((deprecated("Use watch_disable_leds instead")))
|
|
||||||
void watch_disable_led(bool unused);
|
|
||||||
/// @}
|
/// @}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -52,14 +52,15 @@ void watch_display_character(uint8_t character, uint8_t position) {
|
||||||
if (character == 'T') character = 't'; // uppercase T only works in positions 0 and 1
|
if (character == 'T') character = 't'; // uppercase T only works in positions 0 and 1
|
||||||
}
|
}
|
||||||
if (position == 1) {
|
if (position == 1) {
|
||||||
if (character == 'o') character = 'O'; // O needs to be uppercase
|
if (character == 'a') character = 'A'; // A needs to be uppercase
|
||||||
if (character == 'i') character = 'l'; // I needs to be uppercase (use an l, it looks the same)
|
else if (character == 'o') character = 'O'; // O needs to be uppercase
|
||||||
if (character == 'n') character = 'N'; // N needs to be uppercase
|
else if (character == 'i') character = 'l'; // I needs to be uppercase (use an l, it looks the same)
|
||||||
if (character == 'r') character = 'R'; // R needs to be uppercase
|
else if (character == 'n') character = 'N'; // N needs to be uppercase
|
||||||
if (character == 'd') character = 'D'; // D needs to be uppercase
|
else if (character == 'r') character = 'R'; // R needs to be uppercase
|
||||||
if (character == 'v' || character == 'V' || character == 'u') character = 'U'; // side segments shared, make uppercase
|
else if (character == 'd') character = 'D'; // D needs to be uppercase
|
||||||
if (character == 'b') character = 'B'; // B needs to be uppercase
|
else if (character == 'v' || character == 'V' || character == 'u') character = 'U'; // side segments shared, make uppercase
|
||||||
if (character == 'c') character = 'C'; // C needs to be uppercase
|
else if (character == 'b') character = 'B'; // B needs to be uppercase
|
||||||
|
else if (character == 'c') character = 'C'; // C needs to be uppercase
|
||||||
} else {
|
} else {
|
||||||
if (character == 'R') character = 'r'; // R needs to be lowercase almost everywhere
|
if (character == 'R') character = 'r'; // R needs to be lowercase almost everywhere
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,14 +33,14 @@ static const uint8_t Character_Set[] =
|
||||||
0b01100000, // ! (L in the top half for positions 4 and 6)
|
0b01100000, // ! (L in the top half for positions 4 and 6)
|
||||||
0b00100010, // "
|
0b00100010, // "
|
||||||
0b01100011, // # (degree symbol, hash mark doesn't fit)
|
0b01100011, // # (degree symbol, hash mark doesn't fit)
|
||||||
0b00000000, // $ (unused)
|
0b00101101, // $ (S without the center segment)
|
||||||
0b00000000, // % (unused)
|
0b00000000, // % (unused)
|
||||||
0b01000100, // & ("lowercase 7" for positions 4 and 6)
|
0b01000100, // & ("lowercase 7" for positions 4 and 6)
|
||||||
0b00100000, // '
|
0b00100000, // '
|
||||||
0b00111001, // (
|
0b00111001, // (
|
||||||
0b00001111, // )
|
0b00001111, // )
|
||||||
0b00000000, // * (unused)
|
0b11000000, // * (The + sign for use in position 0)
|
||||||
0b11000000, // + (only works in position 0)
|
0b01110000, // + (segments E, F and G; looks like ┣╸)
|
||||||
0b00000100, // ,
|
0b00000100, // ,
|
||||||
0b01000000, // -
|
0b01000000, // -
|
||||||
0b01000000, // . (same as -, semantically most useful)
|
0b01000000, // . (same as -, semantically most useful)
|
||||||
|
@ -120,9 +120,9 @@ static const uint8_t Character_Set[] =
|
||||||
0b01111110, // x
|
0b01111110, // x
|
||||||
0b01101110, // y
|
0b01101110, // y
|
||||||
0b00011011, // z
|
0b00011011, // z
|
||||||
0b00111001, // {
|
0b00010110, // { (open brace doesn't really work; overriden to represent the two character ligature "il")
|
||||||
0b00110000, // |
|
0b00110110, // | (overriden to represent the two character ligature "ll")
|
||||||
0b00001111, // }
|
0b00110100, // } (overriden to represent the two character ligature "li")
|
||||||
0b00000001, // ~
|
0b00000001, // ~
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -147,24 +147,5 @@ void watch_rtc_disable_matching_periodic_callbacks(uint8_t mask);
|
||||||
*/
|
*/
|
||||||
void watch_rtc_disable_all_periodic_callbacks(void);
|
void watch_rtc_disable_all_periodic_callbacks(void);
|
||||||
|
|
||||||
/** @brief Sets the system date and time.
|
|
||||||
* @param date_time A struct representing the date and time you wish to set.
|
|
||||||
*/
|
|
||||||
__attribute__((deprecated("Use watch_rtc_set_date_time function instead")))
|
|
||||||
void watch_set_date_time(struct calendar_date_time date_time);
|
|
||||||
|
|
||||||
/** @brief Returns the system date and time in the provided struct.
|
|
||||||
* @param date_time A pointer to a calendar_date_time struct. It will have with the correct date and time on return.
|
|
||||||
*/
|
|
||||||
__attribute__((deprecated("Use the watch_rtc_get_date_time function instead")))
|
|
||||||
void watch_get_date_time(struct calendar_date_time *date_time);
|
|
||||||
|
|
||||||
/** @brief Registers a "tick" callback that will be called once per second.
|
|
||||||
* @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick
|
|
||||||
* interrupt will still be enabled, but no callback function will be called.
|
|
||||||
*/
|
|
||||||
__attribute__((deprecated("Use the watch_rtc_register_tick_callback function instead")))
|
|
||||||
void watch_register_tick_callback(ext_irq_cb_t callback);
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -52,24 +52,5 @@ void watch_uart_puts(char *s);
|
||||||
*/
|
*/
|
||||||
char watch_uart_getc(void);
|
char watch_uart_getc(void);
|
||||||
|
|
||||||
// Begin deprecated functions:
|
|
||||||
|
|
||||||
/** @brief Initializes the debug UART.
|
|
||||||
* @param baud The baud rate
|
|
||||||
*/
|
|
||||||
__attribute__((deprecated("Use watch_enable_uart to enable the UART.")))
|
|
||||||
void watch_enable_debug_uart(uint32_t baud);
|
|
||||||
|
|
||||||
/** @brief Outputs a single character on the debug UART.
|
|
||||||
* @param c The character you wish to output.
|
|
||||||
*/
|
|
||||||
__attribute__((deprecated("Use watch_uart_puts to print to the UART, or printf to log debug messages over USB.")))
|
|
||||||
void watch_debug_putc(char c);
|
|
||||||
|
|
||||||
/** @brief Outputs a string on the debug UART.
|
|
||||||
* @param s A null-terminated string.
|
|
||||||
*/
|
|
||||||
__attribute__((deprecated("Use watch_uart_puts to print to the UART, or printf to log debug messages over USB.")))
|
|
||||||
void watch_debug_puts(char *s);
|
|
||||||
/// @}
|
/// @}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -188,3 +188,11 @@ float watch_utility_thermistor_temperature(uint16_t value, bool highside, float
|
||||||
|
|
||||||
return reading;
|
return reading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t watch_utility_offset_timestamp(uint32_t now, int8_t hours, int8_t minutes, int8_t seconds) {
|
||||||
|
uint32_t new = now;
|
||||||
|
new += hours * 60 * 60;
|
||||||
|
new += minutes * 60;
|
||||||
|
new += seconds;
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ uint32_t watch_utility_date_time_to_unix_time(watch_date_time date_time, uint32_
|
||||||
*/
|
*/
|
||||||
watch_duration_t watch_utility_seconds_to_duration(uint32_t seconds);
|
watch_duration_t watch_utility_seconds_to_duration(uint32_t seconds);
|
||||||
|
|
||||||
/** @brief Returns the UNIX time (seconds since 1970) for a given watch_date_time struct.
|
/** @brief Returns a watch_date_time struct for a given UNIX time and UTC offset.
|
||||||
* @param timestamp The UNIX timestamp that you wish to convert.
|
* @param timestamp The UNIX timestamp that you wish to convert.
|
||||||
* @param utc_offset The number of seconds that you wish date_time to be offset from UTC.
|
* @param utc_offset The number of seconds that you wish date_time to be offset from UTC.
|
||||||
* @return A watch_date_time for the given UNIX timestamp and UTC offset, or if outside the range that
|
* @return A watch_date_time for the given UNIX timestamp and UTC offset, or if outside the range that
|
||||||
|
@ -124,4 +124,12 @@ watch_date_time watch_utility_date_time_convert_zone(watch_date_time date_time,
|
||||||
*/
|
*/
|
||||||
float watch_utility_thermistor_temperature(uint16_t value, bool highside, float b_coefficient, float nominal_temperature, float nominal_resistance, float series_resistance);
|
float watch_utility_thermistor_temperature(uint16_t value, bool highside, float b_coefficient, float nominal_temperature, float nominal_resistance, float series_resistance);
|
||||||
|
|
||||||
|
/** @brief Offset a timestamp by a given amount
|
||||||
|
* @param now Timestamp to offset from
|
||||||
|
* @param hours Number of hours to offset
|
||||||
|
* @param minutes Nmber of minutes to offset
|
||||||
|
* @param seconds Number of secodns to offset
|
||||||
|
*/
|
||||||
|
uint32_t watch_utility_offset_timestamp(uint32_t now, int8_t hours, int8_t minutes, int8_t seconds);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,7 +29,7 @@ void watch_enable_adc(void) {}
|
||||||
void watch_enable_analog_input(const uint8_t pin) {}
|
void watch_enable_analog_input(const uint8_t pin) {}
|
||||||
|
|
||||||
uint16_t watch_get_analog_pin_level(const uint8_t pin) {
|
uint16_t watch_get_analog_pin_level(const uint8_t pin) {
|
||||||
return 0;
|
return 32767; // pretend it's half of VCC
|
||||||
}
|
}
|
||||||
|
|
||||||
void watch_set_analog_num_samples(uint16_t samples) {}
|
void watch_set_analog_num_samples(uint16_t samples) {}
|
||||||
|
|
|
@ -86,15 +86,3 @@ void watch_enter_backup_mode(void) {
|
||||||
// go into backup sleep mode (5). when we exit, the reset controller will take over.
|
// go into backup sleep mode (5). when we exit, the reset controller will take over.
|
||||||
// sleep(5);
|
// sleep(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// deprecated
|
|
||||||
void watch_enter_shallow_sleep(bool display_on) {
|
|
||||||
if (display_on) watch_enter_sleep_mode();
|
|
||||||
else watch_enter_deep_sleep_mode();
|
|
||||||
}
|
|
||||||
|
|
||||||
// deprecated
|
|
||||||
void watch_enter_deep_sleep(void) {
|
|
||||||
watch_register_extwake_callback(BTN_ALARM, NULL, true);
|
|
||||||
watch_enter_backup_mode();
|
|
||||||
}
|
|
||||||
|
|
|
@ -181,11 +181,3 @@ void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback,
|
||||||
external_interrupt_alarm_trigger = trigger;
|
external_interrupt_alarm_trigger = trigger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void watch_register_button_callback(const uint8_t pin, ext_irq_cb_t callback) {
|
|
||||||
watch_register_interrupt_callback(pin, callback, INTERRUPT_TRIGGER_RISING);
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_enable_buttons(void) {
|
|
||||||
watch_enable_external_interrupts();
|
|
||||||
}
|
|
||||||
|
|
|
@ -30,16 +30,6 @@ void watch_enable_leds(void) {}
|
||||||
|
|
||||||
void watch_disable_leds(void) {}
|
void watch_disable_leds(void) {}
|
||||||
|
|
||||||
void watch_enable_led(bool unused) {
|
|
||||||
(void)unused;
|
|
||||||
watch_enable_leds();
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_disable_led(bool unused) {
|
|
||||||
(void)unused;
|
|
||||||
watch_disable_leds();
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_set_led_color(uint8_t red, uint8_t green) {
|
void watch_set_led_color(uint8_t red, uint8_t green) {
|
||||||
EM_ASM({
|
EM_ASM({
|
||||||
document.getElementById('light').style.opacity = $1 / 255;
|
document.getElementById('light').style.opacity = $1 / 255;
|
||||||
|
|
|
@ -67,12 +67,3 @@ int _write(int file, char *ptr, int len) {
|
||||||
int _read(void) {
|
int _read(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alternate function that outputs to the debug UART. useful for debugging USB issues.
|
|
||||||
// int _write(int file, char *ptr, int len) {
|
|
||||||
// (void)file;
|
|
||||||
// int pos = 0;
|
|
||||||
// while(pos < len) watch_debug_putc(ptr[pos++]);
|
|
||||||
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
|
@ -197,32 +197,3 @@ void watch_rtc_disable_alarm_callback(void) {
|
||||||
alarm_interval_id = -1;
|
alarm_interval_id = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////
|
|
||||||
// Deprecated functions
|
|
||||||
|
|
||||||
void watch_set_date_time(struct calendar_date_time date_time) {
|
|
||||||
watch_date_time val;
|
|
||||||
val.unit.second = date_time.time.sec;
|
|
||||||
val.unit.minute = date_time.time.min;
|
|
||||||
val.unit.hour = date_time.time.hour;
|
|
||||||
val.unit.day = date_time.date.day;
|
|
||||||
val.unit.month = date_time.date.month;
|
|
||||||
val.unit.year = date_time.date.year - WATCH_RTC_REFERENCE_YEAR;
|
|
||||||
watch_rtc_set_date_time(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_get_date_time(struct calendar_date_time *date_time) {
|
|
||||||
if (date_time == NULL) return;
|
|
||||||
watch_date_time val = watch_rtc_get_date_time();
|
|
||||||
date_time->time.sec = val.unit.second;
|
|
||||||
date_time->time.min = val.unit.minute;
|
|
||||||
date_time->time.hour = val.unit.hour;
|
|
||||||
date_time->date.day = val.unit.day;
|
|
||||||
date_time->date.month = val.unit.month;
|
|
||||||
date_time->date.year = val.unit.year + WATCH_RTC_REFERENCE_YEAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_register_tick_callback(ext_irq_cb_t callback) {
|
|
||||||
watch_rtc_register_tick_callback(callback);
|
|
||||||
}
|
|
||||||
|
|
|
@ -45,14 +45,3 @@ char watch_uart_getc(void) {
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void watch_enable_debug_uart(uint32_t baud) {}
|
|
||||||
|
|
||||||
void watch_debug_putc(char c) {}
|
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
void watch_debug_puts(char *s) {
|
|
||||||
while (*s) watch_debug_putc(*s++);
|
|
||||||
}
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
Loading…
Reference in a new issue